tangled
alpha
login
or
join now
baileytownsend.dev
/
pds-moover
126
fork
atom
Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations.
pdsmoover.com
pds
atproto
migrations
moo
cow
126
fork
atom
overview
issues
2
pulls
1
pipelines
missing blobs and better upload status
baileytownsend.dev
7 months ago
0f931222
c53d8592
+52
-7
2 changed files
expand all
collapse all
unified
split
index.html
src
pdsmoover.js
+2
-2
index.html
···
169
</form>
170
<div x-show="askForPlcToken" class="section">
171
<form @submit.prevent="await signPlcOperation()">
172
-
<h2>Please enter your PLCToken you received in an email</h2>
173
<div class="form-group">
174
-
<label for="plc-token">PLCToken:</label>
175
<input type="text" id="plc-token" name="plc-token" x-model="plcToken" required>
176
</div>
177
<div x-show="error" x-text="error" class="error-message"></div>
···
169
</form>
170
<div x-show="askForPlcToken" class="section">
171
<form @submit.prevent="await signPlcOperation()">
172
+
<h2>Please enter your PLC Token you received in an email</h2>
173
<div class="form-group">
174
+
<label for="plc-token">PLC Token:</label>
175
<input type="text" id="plc-token" name="plc-token" x-model="plcToken" required>
176
</div>
177
<div x-show="error" x-text="error" class="error-message"></div>
+50
-5
src/pdsmoover.js
···
35
constructor() {
36
this.oldAgent = null;
37
this.newAgent = null;
0
38
}
39
40
/**
···
77
await oldAgent.login({identifier: oldHandle, password: password, authFactorToken: twoFactorCode});
78
}
79
80
-
safeStatusUpdate(statusUpdateHandler, 'Checking that the new PDS is an actual PDS');
81
const newAgent = new AtpAgent({service: newPdsUrl});
82
const newHostDesc = await newAgent.com.atproto.server.describeServer();
83
const newHostWebDid = newHostDesc.data.did;
···
110
111
await newAgent.login({
112
identifier: usersDid,
113
-
password,
114
});
115
116
safeStatusUpdate(statusUpdateHandler, 'Migrating your repo');
···
119
encoding: 'application/vnd.ipld.car',
120
});
121
0
122
safeStatusUpdate(statusUpdateHandler, 'Migrating your blobs');
123
124
let blobCursor = undefined;
125
let uploadedBlobs = 0;
126
do {
127
-
safeStatusUpdate(statusUpdateHandler, `Migrating blobs, ${uploadedBlobs}/${uploadedBlobs + 100}`);
128
-
uploadedBlobs += 100;
129
const listedBlobs = await oldAgent.com.atproto.sync.listBlobs({
130
did: usersDid,
131
cursor: blobCursor,
132
limit: 100,
133
});
0
134
for (const cid of listedBlobs.data.cids) {
135
try {
136
//TODO may move the status update here but would have it only update like every 10
···
141
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
142
encoding: blobRes.headers['content-type'],
143
});
0
0
0
0
144
} catch (error) {
145
//TODO silently logging for now will do a missing blobs later
146
console.error(error);
···
149
blobCursor = listedBlobs.data.cursor;
150
} while (blobCursor);
151
152
-
//TODO NEED to do some checking on the missing blobs here
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
153
154
const prefs = await oldAgent.app.bsky.actor.getPreferences();
155
await newAgent.app.bsky.actor.putPreferences(prefs.data);
···
35
constructor() {
36
this.oldAgent = null;
37
this.newAgent = null;
38
+
this.missingBlobs = [];
39
}
40
41
/**
···
78
await oldAgent.login({identifier: oldHandle, password: password, authFactorToken: twoFactorCode});
79
}
80
81
+
safeStatusUpdate(statusUpdateHandler, 'Checking that the new PDS is an actual PDS (if the url is wrong this takes a while to error out)');
82
const newAgent = new AtpAgent({service: newPdsUrl});
83
const newHostDesc = await newAgent.com.atproto.server.describeServer();
84
const newHostWebDid = newHostDesc.data.did;
···
111
112
await newAgent.login({
113
identifier: usersDid,
114
+
password: password,
115
});
116
117
safeStatusUpdate(statusUpdateHandler, 'Migrating your repo');
···
120
encoding: 'application/vnd.ipld.car',
121
});
122
123
+
let newAccountStatus = await newAgent.com.atproto.server.checkAccountStatus();
124
safeStatusUpdate(statusUpdateHandler, 'Migrating your blobs');
125
126
let blobCursor = undefined;
127
let uploadedBlobs = 0;
128
do {
129
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`);
130
+
131
const listedBlobs = await oldAgent.com.atproto.sync.listBlobs({
132
did: usersDid,
133
cursor: blobCursor,
134
limit: 100,
135
});
136
+
137
for (const cid of listedBlobs.data.cids) {
138
try {
139
//TODO may move the status update here but would have it only update like every 10
···
144
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
145
encoding: blobRes.headers['content-type'],
146
});
147
+
uploadedBlobs++;
148
+
if (uploadedBlobs % 10 === 0) {
149
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`);
150
+
}
151
} catch (error) {
152
//TODO silently logging for now will do a missing blobs later
153
console.error(error);
···
156
blobCursor = listedBlobs.data.cursor;
157
} while (blobCursor);
158
159
+
newAccountStatus = await newAgent.com.atproto.server.checkAccountStatus();
160
+
if (newAccountStatus.data.expectedBlobs !== uploadedBlobs) {
161
+
let totalMissingBlobs = newAccountStatus.data.expectedBlobs - uploadedBlobs;
162
+
safeStatusUpdate(statusUpdateHandler, 'Looks like there are some missing blobs. Going to try and upload them now.');
163
+
//Probably should be shared between main blob uploader, but eh
164
+
let missingBlobCursor = undefined;
165
+
let missingUploadedBlobs = 0;
166
+
do {
167
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`);
168
+
169
+
const missingBlobs = await oldAgent.com.atproto.repo.listMissingBlobs({
170
+
did: usersDid,
171
+
cursor: missingBlobCursor,
172
+
limit: 100,
173
+
});
174
+
175
+
for (const cid of missingBlobs.data.cids) {
176
+
try {
177
+
//TODO may move the status update here but would have it only update like every 10
178
+
const blobRes = await oldAgent.com.atproto.sync.getBlob({
179
+
cid,
180
+
});
181
+
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
182
+
encoding: blobRes.headers['content-type'],
183
+
});
184
+
if (uploadedBlobs % 10 === 0) {
185
+
safeStatusUpdate(statusUpdateHandler, `Migrating blobs: ${uploadedBlobs}/${uploadedBlobs}`);
186
+
}
187
+
uploadedBlobs++;
188
+
} catch (error) {
189
+
//TODO silently logging for now will do a missing blobs later
190
+
console.error(error);
191
+
this.missingBlobs.push(cid);
192
+
}
193
+
}
194
+
missingBlobCursor = missingBlobs.data.cursor;
195
+
} while (missingBlobCursor);
196
+
197
+
}
198
199
const prefs = await oldAgent.app.bsky.actor.getPreferences();
200
await newAgent.app.bsky.actor.putPreferences(prefs.data);