Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations. pdsmoover.com
pds atproto migrations moo cow
at next 4.8 kB view raw
1//I need to condense this code with the rest of PDS MOOver cause it has a lot of overlap 2import {AtpAgent} from '@atproto/api'; 3import {handleAndPDSResolver} from './atprotoUtils.js'; 4 5 6class MissingBlobs { 7 8 constructor() { 9 this.currentPdsAgent = null; 10 this.oldPdsAgent = null; 11 this.did = null; 12 this.currentPdsUrl = null; 13 this.missingBlobs = []; 14 15 } 16 17 async currentAgentLogin( 18 handle, 19 password, 20 twoFactorCode = null, 21 ) { 22 let {usersDid, pds} = await handleAndPDSResolver(handle); 23 this.did = usersDid; 24 this.currentPdsUrl = pds; 25 const agent = new AtpAgent({ 26 service: pds, 27 }); 28 29 if (twoFactorCode === null) { 30 await agent.login({identifier: usersDid, password}); 31 } else { 32 await agent.login({identifier: usersDid, password: password, authFactorToken: twoFactorCode}); 33 } 34 35 this.currentPdsAgent = agent; 36 37 const result = await agent.com.atproto.server.checkAccountStatus(); 38 const missingBlobs = await this.currentPdsAgent.com.atproto.repo.listMissingBlobs({ 39 limit: 10, 40 }); 41 return {accountStatus: result.data, missingBlobsCount: missingBlobs.data.blobs.length}; 42 } 43 44 async oldAgentLogin( 45 password, 46 twoFactorCode = null, 47 pdsUrl = null, 48 ) { 49 let oldPds = null; 50 51 if (pdsUrl === null) { 52 const response = await fetch(`https://plc.directory/${this.did}/log`); 53 let auditLog = await response.json(); 54 auditLog = auditLog.reverse(); 55 let debugCount = 0; 56 for (const entry of auditLog) { 57 console.log(`Loop: ${debugCount++}`); 58 console.log(entry); 59 if (entry.services) { 60 if (entry.services.atproto_pds) { 61 if (entry.services.atproto_pds.type === 'AtprotoPersonalDataServer') { 62 const pds = entry.services.atproto_pds.endpoint; 63 console.log(`Found PDS: ${pds}`); 64 if (pds.toLowerCase() !== this.currentPdsUrl.toLowerCase()) { 65 oldPds = pds; 66 break; 67 } 68 } 69 } 70 } 71 } 72 if (oldPds === null) { 73 throw new Error('Could not find your old PDS'); 74 } 75 } else { 76 oldPds = pdsUrl; 77 } 78 79 const agent = new AtpAgent({ 80 service: oldPds, 81 }); 82 83 if (twoFactorCode === null) { 84 await agent.login({identifier: this.did, password}); 85 } else { 86 await agent.login({identifier: this.did, password: password, authFactorToken: twoFactorCode}); 87 } 88 this.oldPdsAgent = agent; 89 } 90 91 async migrateMissingBlobs(statusUpdateHandler) { 92 if (this.currentPdsAgent === null) { 93 throw new Error('Current PDS agent is not set'); 94 } 95 if (this.oldPdsAgent === null) { 96 throw new Error('Old PDS agent is not set'); 97 } 98 statusUpdateHandler('Starting to import blobs...'); 99 100 // const currentAccountStatus = await this.currentPdsAgent.com.atproto.server.checkAccountStatus(); 101 // let totalMissingBlobs = currentAccountStatus.data.expectedBlobs - currentAccountStatus.data.importedBlobs; 102 let totalMissingBlobs = 0; 103 let missingBlobCursor = undefined; 104 let missingUploadedBlobs = 0; 105 106 do { 107 108 const missingBlobs = await this.currentPdsAgent.com.atproto.repo.listMissingBlobs({ 109 cursor: missingBlobCursor, 110 //Test this cause it may be a big update 111 limit: 1000, 112 }); 113 totalMissingBlobs += missingBlobs.data.blobs.length; 114 115 for (const recordBlob of missingBlobs.data.blobs) { 116 try { 117 118 const blobRes = await this.oldPdsAgent.com.atproto.sync.getBlob({ 119 did: this.did, 120 cid: recordBlob.cid, 121 }); 122 let result = await this.currentPdsAgent.com.atproto.repo.uploadBlob(blobRes.data, { 123 encoding: blobRes.headers['content-type'], 124 }); 125 126 if (result.status === 429) { 127 statusUpdateHandler(`You are being rate limited. Will need to try again later to get the rest of the blobs. Migrated blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`); 128 } 129 130 if (missingUploadedBlobs % 2 === 0) { 131 statusUpdateHandler(`Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs} (The total may increase as we find more)`); 132 } 133 missingUploadedBlobs++; 134 } catch (error) { 135 console.error(error); 136 this.missingBlobs.push(recordBlob.cid); 137 } 138 } 139 missingBlobCursor = missingBlobs.data.cursor; 140 } while (missingBlobCursor); 141 142 const accountStatus = await this.currentPdsAgent.com.atproto.server.checkAccountStatus(); 143 const missingBlobs = await this.currentPdsAgent.com.atproto.repo.listMissingBlobs({ 144 limit: 10, 145 }); 146 return {accountStatus: accountStatus.data, missingBlobsCount: missingBlobs.data.blobs.length}; 147 148 149 } 150 151} 152 153export {MissingBlobs};