MOOre features #1

merged
opened by baileytownsend.dev targeting main from feature/RetryLogicAndInfo
  • missing blobs
  • retry flags
  • info
Changed files
+96 -88
public
src
+93 -86
src/pdsmoover.js
···
this.newAgent = null;
this.missingBlobs = [];
//State for reruns
-
this.oldAccountStatus = null;
-
this.newAccountStatus = null;
this.createNewAccount = true;
this.migrateRepo = true;
this.migrateBlobs = true;
···
safeStatusUpdate(statusUpdateHandler, 'Checking that the new PDS is an actual PDS (if the url is wrong this takes a while to error out)');
const newAgent = new AtpAgent({service: newPdsUrl});
const newHostDesc = await newAgent.com.atproto.server.describeServer();
-
const newHostWebDid = newHostDesc.data.did;
+
if (this.createNewAccount) {
+
const newHostWebDid = newHostDesc.data.did;
-
safeStatusUpdate(statusUpdateHandler, 'Creating a new account on the new PDS');
+
safeStatusUpdate(statusUpdateHandler, 'Creating a new account on the new PDS');
-
const createAuthResp = await oldAgent.com.atproto.server.getServiceAuth({
-
aud: newHostWebDid,
-
lxm: 'com.atproto.server.createAccount',
-
});
-
const serviceJwt = createAuthResp.data.token;
+
const createAuthResp = await oldAgent.com.atproto.server.getServiceAuth({
+
aud: newHostWebDid,
+
lxm: 'com.atproto.server.createAccount',
+
});
+
const serviceJwt = createAuthResp.data.token;
-
const createNewAccount = await newAgent.com.atproto.server.createAccount({
-
did: usersDid,
-
handle: newHandle,
-
email: newEmail,
-
password: password,
-
inviteCode: inviteCode,
-
},
-
{
-
headers: {authorization: `Bearer ${serviceJwt}`},
-
encoding: 'application/json',
-
});
+
const createNewAccount = await newAgent.com.atproto.server.createAccount({
+
did: usersDid,
+
handle: newHandle,
+
email: newEmail,
+
password: password,
+
inviteCode: inviteCode,
+
},
+
{
+
headers: {authorization: `Bearer ${serviceJwt}`},
+
encoding: 'application/json',
+
});
-
if (createNewAccount.data.did !== usersDid.toString()) {
-
throw new Error('Did not create the new account with the same did as the old account');
+
if (createNewAccount.data.did !== usersDid.toString()) {
+
throw new Error('Did not create the new account with the same did as the old account');
+
}
}
-
safeStatusUpdate(statusUpdateHandler, 'Logging in with the new account');
await newAgent.login({
···
password: password,
});
-
safeStatusUpdate(statusUpdateHandler, 'Migrating your repo');
-
const repoRes = await oldAgent.com.atproto.sync.getRepo({did: usersDid});
-
await newAgent.com.atproto.repo.importRepo(repoRes.data, {
-
encoding: 'application/vnd.ipld.car',
-
});
+
if (this.migrateRepo) {
+
safeStatusUpdate(statusUpdateHandler, 'Migrating your repo');
+
const repoRes = await oldAgent.com.atproto.sync.getRepo({did: usersDid});
+
await newAgent.com.atproto.repo.importRepo(repoRes.data, {
+
encoding: 'application/vnd.ipld.car',
+
});
+
}
let newAccountStatus = await newAgent.com.atproto.server.checkAccountStatus();
-
safeStatusUpdate(statusUpdateHandler, 'Migrating your blobs');
-
-
let blobCursor = undefined;
-
let uploadedBlobs = 0;
-
do {
-
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`);
-
const listedBlobs = await oldAgent.com.atproto.sync.listBlobs({
-
did: usersDid,
-
cursor: blobCursor,
-
limit: 100,
-
});
+
if (this.migrateBlobs) {
+
safeStatusUpdate(statusUpdateHandler, 'Migrating your blobs');
-
for (const cid of listedBlobs.data.cids) {
-
try {
-
//TODO may move the status update here but would have it only update like every 10
-
const blobRes = await oldAgent.com.atproto.sync.getBlob({
-
did: usersDid,
-
cid,
-
});
-
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
-
encoding: blobRes.headers['content-type'],
-
});
-
uploadedBlobs++;
-
if (uploadedBlobs % 10 === 0) {
-
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`);
-
}
-
} catch (error) {
-
//TODO silently logging for now will do a missing blobs later
-
console.error(error);
-
}
-
}
-
blobCursor = listedBlobs.data.cursor;
-
} while (blobCursor);
-
-
newAccountStatus = await newAgent.com.atproto.server.checkAccountStatus();
-
if (newAccountStatus.data.expectedBlobs !== uploadedBlobs) {
-
let totalMissingBlobs = newAccountStatus.data.expectedBlobs - uploadedBlobs;
-
safeStatusUpdate(statusUpdateHandler, 'Looks like there are some missing blobs. Going to try and upload them now.');
-
//Probably should be shared between main blob uploader, but eh
-
let missingBlobCursor = undefined;
-
let missingUploadedBlobs = 0;
+
let blobCursor = undefined;
+
let uploadedBlobs = 0;
do {
-
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`);
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`);
-
const missingBlobs = await oldAgent.com.atproto.repo.listMissingBlobs({
+
const listedBlobs = await oldAgent.com.atproto.sync.listBlobs({
did: usersDid,
-
cursor: missingBlobCursor,
+
cursor: blobCursor,
limit: 100,
});
-
for (const cid of missingBlobs.data.cids) {
+
for (const cid of listedBlobs.data.cids) {
try {
-
//TODO may move the status update here but would have it only update like every 10
const blobRes = await oldAgent.com.atproto.sync.getBlob({
+
did: usersDid,
cid,
});
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
encoding: blobRes.headers['content-type'],
});
+
uploadedBlobs++;
if (uploadedBlobs % 10 === 0) {
-
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${uploadedBlobs}`);
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`);
}
-
uploadedBlobs++;
} catch (error) {
-
//TODO silently logging for now will do a missing blobs later
console.error(error);
-
this.missingBlobs.push(cid);
}
}
-
missingBlobCursor = missingBlobs.data.cursor;
-
} while (missingBlobCursor);
-
+
blobCursor = listedBlobs.data.cursor;
+
} while (blobCursor);
}
-
const prefs = await oldAgent.app.bsky.actor.getPreferences();
-
await newAgent.app.bsky.actor.putPreferences(prefs.data);
-
this.oldAgent = oldAgent;
-
this.newAgent = newAgent;
-
await oldAgent.com.atproto.identity.requestPlcOperationSignature();
-
safeStatusUpdate(statusUpdateHandler, 'Please check your email for a PLC token');
+
if (this.migrateMissingBlobs) {
+
newAccountStatus = await newAgent.com.atproto.server.checkAccountStatus();
+
if (newAccountStatus.data.expectedBlobs !== newAccountStatus.data.importedBlobs) {
+
let totalMissingBlobs = newAccountStatus.data.expectedBlobs - newAccountStatus.data.importedBlobs;
+
safeStatusUpdate(statusUpdateHandler, 'Looks like there are some missing blobs. Going to try and upload them now.');
+
//Probably should be shared between main blob uploader, but eh
+
let missingBlobCursor = undefined;
+
let missingUploadedBlobs = 0;
+
do {
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`);
+
+
const missingBlobs = await newAgent.com.atproto.repo.listMissingBlobs({
+
cursor: missingBlobCursor,
+
limit: 100,
+
});
+
for (const recordBlob of missingBlobs.data.blobs) {
+
try {
+
//TODO may move the status update here but would have it only update like every 10
+
const blobRes = await oldAgent.com.atproto.sync.getBlob({
+
did: usersDid,
+
cid: recordBlob.cid,
+
});
+
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
+
encoding: blobRes.headers['content-type'],
+
});
+
if (missingUploadedBlobs % 10 === 0) {
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`);
+
}
+
missingUploadedBlobs++;
+
} catch (error) {
+
//TODO silently logging for now will do a missing blobs later
+
console.error(error);
+
this.missingBlobs.push(cid);
+
}
+
}
+
missingBlobCursor = missingBlobs.data.cursor;
+
} while (missingBlobCursor);
+
+
}
+
}
+
if (this.migratePrefs) {
+
const prefs = await oldAgent.app.bsky.actor.getPreferences();
+
await newAgent.app.bsky.actor.putPreferences(prefs.data);
+
this.oldAgent = oldAgent;
+
this.newAgent = newAgent;
+
}
+
+
if (this.migratePlcRecord) {
+
await oldAgent.com.atproto.identity.requestPlcOperationSignature();
+
safeStatusUpdate(statusUpdateHandler, 'Please check your email for a PLC token');
+
}
}
async signPlcOperation(token) {
+1
public/style.css
···
font-weight: 500;
color: #646cff;
text-decoration: inherit;
+
text-decoration: underline;
}
a:hover {
+2 -2
README.md
···
![moo](./public/moo.webp)
-
Use at your own risk, I will not host till I have a bit more validation and retry logic in place.
-
AND it will still be very much so, use at your own Risk.
+
A no frills client side PDS account migrator for ATProto. For more info check out
+
[pdsmoover.com](https://pdsmoover.com)