//I need to condense this code with the rest of PDS MOOver cause it has a lot of overlap import {AtpAgent} from '@atproto/api'; import {handleAndPDSResolver} from './atprotoUtils.js'; class MissingBlobs { constructor() { this.currentPdsAgent = null; this.oldPdsAgent = null; this.did = null; this.currentPdsUrl = null; this.missingBlobs = []; } async currentAgentLogin( handle, password, twoFactorCode = null, ) { let {usersDid, pds} = await handleAndPDSResolver(handle); this.did = usersDid; this.currentPdsUrl = pds; const agent = new AtpAgent({ service: pds, }); if (twoFactorCode === null) { await agent.login({identifier: usersDid, password}); } else { await agent.login({identifier: usersDid, password: password, authFactorToken: twoFactorCode}); } this.currentPdsAgent = agent; const result = await agent.com.atproto.server.checkAccountStatus(); const missingBlobs = await this.currentPdsAgent.com.atproto.repo.listMissingBlobs({ limit: 10, }); return {accountStatus: result.data, missingBlobsCount: missingBlobs.data.blobs.length}; } async oldAgentLogin( password, twoFactorCode = null, pdsUrl = null, ) { let oldPds = null; if (pdsUrl === null) { const response = await fetch(`https://plc.directory/${this.did}/log`); let auditLog = await response.json(); auditLog = auditLog.reverse(); let debugCount = 0; for (const entry of auditLog) { console.log(`Loop: ${debugCount++}`); console.log(entry); if (entry.services) { if (entry.services.atproto_pds) { if (entry.services.atproto_pds.type === 'AtprotoPersonalDataServer') { const pds = entry.services.atproto_pds.endpoint; console.log(`Found PDS: ${pds}`); if (pds.toLowerCase() !== this.currentPdsUrl.toLowerCase()) { oldPds = pds; break; } } } } } if (oldPds === null) { throw new Error('Could not find your old PDS'); } } else { oldPds = pdsUrl; } const agent = new AtpAgent({ service: oldPds, }); if (twoFactorCode === null) { await agent.login({identifier: this.did, password}); } else { await agent.login({identifier: this.did, password: password, authFactorToken: twoFactorCode}); } this.oldPdsAgent = agent; } async migrateMissingBlobs(statusUpdateHandler) { if (this.currentPdsAgent === null) { throw new Error('Current PDS agent is not set'); } if (this.oldPdsAgent === null) { throw new Error('Old PDS agent is not set'); } statusUpdateHandler('Starting to import blobs...'); // const currentAccountStatus = await this.currentPdsAgent.com.atproto.server.checkAccountStatus(); // let totalMissingBlobs = currentAccountStatus.data.expectedBlobs - currentAccountStatus.data.importedBlobs; let totalMissingBlobs = 0; let missingBlobCursor = undefined; let missingUploadedBlobs = 0; do { const missingBlobs = await this.currentPdsAgent.com.atproto.repo.listMissingBlobs({ cursor: missingBlobCursor, //Test this cause it may be a big update limit: 1000, }); totalMissingBlobs += missingBlobs.data.blobs.length; for (const recordBlob of missingBlobs.data.blobs) { try { const blobRes = await this.oldPdsAgent.com.atproto.sync.getBlob({ did: this.did, cid: recordBlob.cid, }); let result = await this.currentPdsAgent.com.atproto.repo.uploadBlob(blobRes.data, { encoding: blobRes.headers['content-type'], }); if (result.status === 429) { statusUpdateHandler(`You are being rate limited. Will need to try again later to get the rest of the blobs. Migrated blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`); } if (missingUploadedBlobs % 2 === 0) { statusUpdateHandler(`Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs} (The total may increase as we find more)`); } missingUploadedBlobs++; } catch (error) { console.error(error); this.missingBlobs.push(recordBlob.cid); } } missingBlobCursor = missingBlobs.data.cursor; } while (missingBlobCursor); const accountStatus = await this.currentPdsAgent.com.atproto.server.checkAccountStatus(); const missingBlobs = await this.currentPdsAgent.com.atproto.repo.listMissingBlobs({ limit: 10, }); return {accountStatus: accountStatus.data, missingBlobsCount: missingBlobs.data.blobs.length}; } } export {MissingBlobs};