CLI tool for migrating PDS

Data migration

+159 -4
+1 -1
Cargo.toml
··· 4 4 edition = "2021" 5 5 6 6 [dependencies] 7 - atrium-api = { version = "0.25.0", default-features = false, features = ["agent"] } 7 + atrium-api = { version = "0.25.0", default-features = false, features = ["agent", "bluesky"] } 8 8 atrium-xrpc-client = "0.5.11" 9 9 tokio = { version = "1.44.0", features = ["macros", "rt-multi-thread"]}
+158 -3
src/main.rs
··· 1 1 use atrium_api::{ 2 2 agent::atp_agent::{store::MemorySessionStore, AtpAgent}, 3 - com::atproto::server::{create_account, get_service_auth}, 3 + app::bsky::actor::{get_preferences, put_preferences}, 4 + com::atproto::{ 5 + server::{create_account, get_service_auth}, 6 + sync::{get_blob, get_repo, list_blobs}, 7 + }, 4 8 types::string::{Handle, Nsid}, 5 9 }; 6 10 use atrium_xrpc_client::reqwest::ReqwestClient; ··· 58 62 println!(); 59 63 60 64 // Create new account 61 - println!("First migration step is registering an account with your new PDS"); 62 65 let new_pds_url = match readln(Some( 63 66 "Please type in the URL of the PDS you want to migrate to: ", 64 67 )) { ··· 68 71 return; 69 72 } 70 73 }; 74 + println!("Creating an account on your new PDS ..."); 71 75 let new_agent = AtpAgent::new( 72 76 ReqwestClient::new(&new_pds_url), 73 77 MemorySessionStore::default(), ··· 177 181 ) 178 182 .await 179 183 { 184 + Ok(_) => (), 185 + Err(err) => { 186 + println!("com.atproto.server.createAccount at new PDS failed due to error: {err}"); 187 + return; 188 + } 189 + } 190 + println!("Successfully created account on your new PDS!"); 191 + println!(); 192 + 193 + // Migrate data 194 + println!("Migrating your data"); 195 + 196 + let car = match old_agent 197 + .api 198 + .com 199 + .atproto 200 + .sync 201 + .get_repo( 202 + get_repo::ParametersData { 203 + did: old_agent.did().await.unwrap(), 204 + since: None, 205 + } 206 + .into(), 207 + ) 208 + .await 209 + { 180 210 Ok(response) => response, 181 211 Err(err) => { 182 - println!("com.atproto.server.createAccount at new PDS failed due to error: {err}"); 212 + println!("com.atproto.sync.getRepo at current PDS failed due to error: {err}"); 213 + return; 214 + } 215 + }; 216 + 217 + match new_agent.api.com.atproto.repo.import_repo(car).await { 218 + Ok(_) => (), 219 + Err(err) => { 220 + println!("com.atproto.repo.importRepo at new PDS failed due to error: {err}"); 221 + return; 222 + } 223 + } 224 + println!("Repository successfully migrated"); 225 + 226 + let mut listed_blobs = match old_agent 227 + .api 228 + .com 229 + .atproto 230 + .sync 231 + .list_blobs( 232 + list_blobs::ParametersData { 233 + cursor: None, 234 + did: old_agent.did().await.unwrap(), 235 + limit: None, 236 + since: None, 237 + } 238 + .into(), 239 + ) 240 + .await 241 + { 242 + Ok(response) => response, 243 + Err(err) => { 244 + println!("com.atproto.sync.listBlobs at old PDS failed due to error: {err}"); 245 + return; 246 + } 247 + }; 248 + 249 + while listed_blobs.cursor.is_some() { 250 + for cid in listed_blobs.cids.iter() { 251 + let blob = match old_agent 252 + .api 253 + .com 254 + .atproto 255 + .sync 256 + .get_blob( 257 + get_blob::ParametersData { 258 + cid: cid.to_owned(), 259 + did: old_agent.did().await.unwrap(), 260 + } 261 + .into(), 262 + ) 263 + .await 264 + { 265 + Ok(response) => response, 266 + Err(err) => { 267 + println!("com.atproto.sync.getBlob at current PDS failed due to error: {err}"); 268 + return; 269 + } 270 + }; 271 + 272 + match new_agent.api.com.atproto.repo.upload_blob(blob).await { 273 + Ok(_) => (), 274 + Err(err) => { 275 + println!("com.atproto.repo.uploadBlob at new PDS failed due to error: {err}"); 276 + return; 277 + } 278 + }; 279 + } 280 + 281 + listed_blobs = match old_agent 282 + .api 283 + .com 284 + .atproto 285 + .sync 286 + .list_blobs( 287 + list_blobs::ParametersData { 288 + cursor: listed_blobs.cursor.clone(), 289 + did: old_agent.did().await.unwrap(), 290 + limit: None, 291 + since: None, 292 + } 293 + .into(), 294 + ) 295 + .await 296 + { 297 + Ok(response) => response, 298 + Err(err) => { 299 + println!("com.atproto.sync.listBlobs at old PDS failed due to error: {err}"); 300 + return; 301 + } 302 + }; 303 + } 304 + println!("Blobs successfully migrated!"); 305 + 306 + let prefs = match old_agent 307 + .api 308 + .app 309 + .bsky 310 + .actor 311 + .get_preferences(get_preferences::ParametersData {}.into()) 312 + .await 313 + { 314 + Ok(response) => response, 315 + Err(err) => { 316 + println!("app.bsky.actor.getPreferences at current PDS failed due to error: {err}"); 183 317 return; 184 318 } 185 319 }; 320 + 321 + match new_agent 322 + .api 323 + .app 324 + .bsky 325 + .actor 326 + .put_preferences( 327 + put_preferences::InputData { 328 + preferences: prefs.preferences.clone(), 329 + } 330 + .into(), 331 + ) 332 + .await 333 + { 334 + Ok(_) => (), 335 + Err(err) => { 336 + println!("app.bsky.actor.putPreferences at new PDS failed due to error: {err}"); 337 + return; 338 + } 339 + } 340 + println!("Preferences successfully migrated!"); 186 341 }