braidfs 0.0.153 → 0.0.155
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +112 -51
- package/index.sh +6 -4
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -541,8 +541,6 @@ function sync_url(url) {
|
|
|
541
541
|
var res = await braid_fetch(url, {
|
|
542
542
|
signal: self.ac.signal,
|
|
543
543
|
method: 'HEAD',
|
|
544
|
-
// version needed to force Merge-Type return header
|
|
545
|
-
version: [],
|
|
546
544
|
// setting subscribe shouldn't work according to spec,
|
|
547
545
|
// but it does for some old braid-text servers
|
|
548
546
|
subscribe: !!try_sub,
|
|
@@ -565,15 +563,16 @@ function sync_url(url) {
|
|
|
565
563
|
}
|
|
566
564
|
}
|
|
567
565
|
} catch (e) {
|
|
568
|
-
if (
|
|
569
|
-
}
|
|
570
|
-
if (self.ac.signal.aborted) return
|
|
566
|
+
if (self.ac.signal.aborted) return
|
|
571
567
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
568
|
+
// Retry with increasing delays: 1s, 2s, 3s, 3s, 3s...
|
|
569
|
+
var delay = Math.min(++retry_count, 3)
|
|
570
|
+
console.log(`retrying in ${delay}s: ${url} after error: ${e}`)
|
|
571
|
+
await new Promise(r => setTimeout(r, delay * 1000))
|
|
572
|
+
if (self.ac.signal.aborted) return
|
|
573
|
+
continue
|
|
574
|
+
}
|
|
575
|
+
throw new Error(`no merge-type detected for url: ${url}`)
|
|
577
576
|
}
|
|
578
577
|
}
|
|
579
578
|
|
|
@@ -1083,6 +1082,7 @@ function sync_url(url) {
|
|
|
1083
1082
|
braid_text.get(url, {
|
|
1084
1083
|
signal: ac.signal,
|
|
1085
1084
|
peer: file_peer,
|
|
1085
|
+
merge_type: 'dt',
|
|
1086
1086
|
head: true,
|
|
1087
1087
|
subscribe: () => {
|
|
1088
1088
|
if (self.ac.signal.aborted) return
|
|
@@ -1090,6 +1090,22 @@ function sync_url(url) {
|
|
|
1090
1090
|
}
|
|
1091
1091
|
})
|
|
1092
1092
|
|
|
1093
|
+
// Debugging: Print out changes in memory usage
|
|
1094
|
+
;(async () => {
|
|
1095
|
+
var before = process.memoryUsage().heapUsed
|
|
1096
|
+
try {
|
|
1097
|
+
var r = await braid_text.get(url, { full_response: true })
|
|
1098
|
+
if (self.ac.signal.aborted) return
|
|
1099
|
+
var after = process.memoryUsage().heapUsed
|
|
1100
|
+
console.log(`${url}: +${((after - before) / 1e6).toFixed(1)} MB`
|
|
1101
|
+
+ ` (heap now ${(after / 1e6).toFixed(0)} MB,`
|
|
1102
|
+
+ ` body ${(r?.body?.length || 0)} chars)`)
|
|
1103
|
+
} catch (e) {
|
|
1104
|
+
if (e?.name !== 'AbortError')
|
|
1105
|
+
console.log(`DOC-MEM ${url}: probe error ${e}`)
|
|
1106
|
+
}
|
|
1107
|
+
})()
|
|
1108
|
+
|
|
1093
1109
|
// Use braid_text.sync for bidirectional sync with the remote URL
|
|
1094
1110
|
if (is_external_link) braid_text.sync(url, new URL(url), {
|
|
1095
1111
|
|
|
@@ -1173,81 +1189,126 @@ async function ensure_path(path) {
|
|
|
1173
1189
|
}
|
|
1174
1190
|
}
|
|
1175
1191
|
|
|
1192
|
+
// Rate Limiting Behavior:
|
|
1193
|
+
//
|
|
1194
|
+
// - If nothing is connected (totally offline), then give one turn per 3s
|
|
1195
|
+
// - Pick first host, and resolve first ticket for that host
|
|
1196
|
+
//
|
|
1197
|
+
// - If any host is connected:
|
|
1198
|
+
// - Give a turn to everyone else with tickets for that host
|
|
1199
|
+
// - Give a turn to one ticket for disconnected hosts, per 3s
|
|
1176
1200
|
function ReconnectRateLimiter(wait_time) {
|
|
1177
1201
|
var self = {}
|
|
1178
1202
|
|
|
1179
1203
|
self.conns = new Map() // Map<host, Set<url>>
|
|
1180
|
-
self.
|
|
1181
|
-
self.qs = [] // Array<{
|
|
1182
|
-
self.
|
|
1204
|
+
self.host_to_tickets = new Map() // Map<hostname, Array<ticket>>
|
|
1205
|
+
self.qs = [] // Array<{hostname, tickets: Array<ticket>, latest_turn}>
|
|
1206
|
+
self.latest_turn = 0
|
|
1183
1207
|
self.timer = null
|
|
1184
1208
|
|
|
1185
|
-
|
|
1209
|
+
// Resolves a batch of calls to `await get_turn(url)`.
|
|
1210
|
+
// - It may be just one
|
|
1211
|
+
// - Or it may be many
|
|
1212
|
+
// - Or it may be nothing
|
|
1213
|
+
// - If the wait_time has not expired
|
|
1214
|
+
// - Or if the queue of tickets is empty
|
|
1215
|
+
function give_turns () {
|
|
1186
1216
|
if (self.timer) clearTimeout(self.timer)
|
|
1187
1217
|
self.timer = null
|
|
1188
1218
|
|
|
1189
1219
|
if (!self.qs.length) return
|
|
1190
|
-
var
|
|
1191
|
-
var
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1220
|
+
var fully_disconnected = () => self.conns.size === 0
|
|
1221
|
+
var now = Date.now(),
|
|
1222
|
+
ticket_turn_time = () => wait_time + (fully_disconnected()
|
|
1223
|
+
? self.latest_turn
|
|
1224
|
+
: self.qs[0].latest_turn)
|
|
1225
|
+
|
|
1226
|
+
// Go through the queue of hosts and tickets, to pick some to resolve
|
|
1227
|
+
while (self.qs.length && now >= ticket_turn_time()) {
|
|
1228
|
+
// Remove the first host from top of the queue
|
|
1229
|
+
var host = self.qs.shift()
|
|
1230
|
+
|
|
1231
|
+
// Garbage collect hosts without tickets
|
|
1232
|
+
if (host.tickets.length === 0) {
|
|
1233
|
+
self.host_to_tickets.delete(host.hostname)
|
|
1197
1234
|
continue
|
|
1198
1235
|
}
|
|
1199
1236
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1237
|
+
// Give this ticket holder a turn!
|
|
1238
|
+
host.tickets.shift()()
|
|
1239
|
+
|
|
1240
|
+
// And reinsert the host back to the end
|
|
1241
|
+
self.qs.push(host)
|
|
1242
|
+
host.latest_turn = self.latest_turn = now
|
|
1203
1243
|
}
|
|
1204
1244
|
|
|
1245
|
+
// Set timer for the next round of get_turns() to run
|
|
1205
1246
|
if (self.qs.length)
|
|
1206
|
-
self.timer = setTimeout(
|
|
1207
|
-
|
|
1247
|
+
self.timer = setTimeout(give_turns,
|
|
1248
|
+
Math.max(0, ticket_turn_time() - now))
|
|
1208
1249
|
}
|
|
1209
1250
|
|
|
1210
1251
|
self.get_turn = async (url) => {
|
|
1211
|
-
var
|
|
1252
|
+
var hostname = new URL(url).host
|
|
1212
1253
|
|
|
1213
1254
|
// If host has connections, give turn immediately
|
|
1214
|
-
if (self.conns.has(
|
|
1255
|
+
if (self.conns.has(hostname)) return
|
|
1215
1256
|
|
|
1216
|
-
// console.log(`throttling reconn to ${url} (no conns yet to ${self.conns.size ?
|
|
1257
|
+
// console.log(`throttling reconn to ${url} (no conns yet to ${self.conns.size ? hostname : 'anything'})`)
|
|
1217
1258
|
|
|
1218
|
-
if (!self.
|
|
1219
|
-
var
|
|
1220
|
-
self.
|
|
1221
|
-
self.qs.unshift({
|
|
1259
|
+
if (!self.host_to_tickets.has(hostname)) {
|
|
1260
|
+
var tickets = []
|
|
1261
|
+
self.host_to_tickets.set(hostname, tickets)
|
|
1262
|
+
self.qs.unshift({hostname, tickets, latest_turn: 0})
|
|
1222
1263
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1264
|
+
|
|
1265
|
+
var p = new Promise(resolve =>
|
|
1266
|
+
// This resolve function becomes a ticket!
|
|
1267
|
+
self.host_to_tickets.get(hostname).push(resolve))
|
|
1268
|
+
give_turns()
|
|
1225
1269
|
await p
|
|
1226
1270
|
}
|
|
1227
1271
|
|
|
1272
|
+
// After you get a turn, and connect, it's your responsibility to call
|
|
1273
|
+
// this function to tell the rate limiter that you're online.
|
|
1228
1274
|
self.on_conn = url => {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1275
|
+
// When a host connects, it's time to give a turn to everyone else
|
|
1276
|
+
// with tickets for that host
|
|
1277
|
+
|
|
1278
|
+
var hostname = new URL(url).host
|
|
1279
|
+
|
|
1280
|
+
// We keep track of the connections to each host so that we know which
|
|
1281
|
+
// ones are online and offline.
|
|
1282
|
+
if (!self.conns.has(hostname))
|
|
1283
|
+
self.conns.set(hostname, new Set()) // Initialize the set
|
|
1284
|
+
|
|
1285
|
+
// Add this connection to our memory!
|
|
1286
|
+
self.conns.get(hostname).add(url)
|
|
1233
1287
|
|
|
1234
|
-
// If there are
|
|
1235
|
-
var
|
|
1236
|
-
if (
|
|
1237
|
-
for (var
|
|
1238
|
-
|
|
1288
|
+
// If there are tickets waiting for this host, resolve them all immediately
|
|
1289
|
+
var tickets = self.host_to_tickets.get(hostname)
|
|
1290
|
+
if (tickets) {
|
|
1291
|
+
for (var ticket of tickets) ticket()
|
|
1292
|
+
tickets.splice(0, tickets.length)
|
|
1239
1293
|
}
|
|
1240
1294
|
|
|
1241
|
-
|
|
1295
|
+
give_turns()
|
|
1242
1296
|
}
|
|
1243
1297
|
|
|
1298
|
+
// After you get a turn, and disconnect, it's your responsibility to call
|
|
1299
|
+
// this function to tell the rate limiter that you're offline.
|
|
1244
1300
|
self.on_diss = url => {
|
|
1245
|
-
var
|
|
1246
|
-
var urls = self.conns.get(
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1301
|
+
var hostname = new URL(url).host
|
|
1302
|
+
var urls = self.conns.get(hostname)
|
|
1303
|
+
|
|
1304
|
+
console.assert(urls, 'ReconnectRateLimiter: out of sync! '
|
|
1305
|
+
+ 'Attempt to disconnect from url that is not known to be connected.')
|
|
1306
|
+
|
|
1307
|
+
// Remove this dropped connection from our set!
|
|
1308
|
+
urls.delete(url)
|
|
1309
|
+
|
|
1310
|
+
// And garbage collect the host's connections set if now empty
|
|
1311
|
+
if (urls.size === 0) self.conns.delete(hostname)
|
|
1251
1312
|
}
|
|
1252
1313
|
|
|
1253
1314
|
return self
|
package/index.sh
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
# Function to calculate Base64-encoded SHA256 hash
|
|
4
4
|
calculate_sha256() {
|
|
5
|
-
if command -v
|
|
6
|
-
|
|
5
|
+
if command -v openssl > /dev/null; then
|
|
6
|
+
openssl dgst -sha256 -binary | openssl base64
|
|
7
|
+
elif command -v shasum > /dev/null; then
|
|
8
|
+
shasum -a 256 | cut -d ' ' -f 1 | xxd -r -p | base64
|
|
7
9
|
elif command -v sha256sum > /dev/null; then
|
|
8
|
-
|
|
10
|
+
sha256sum | cut -d ' ' -f 1 | xxd -r -p | base64
|
|
9
11
|
else
|
|
10
|
-
echo "Error:
|
|
12
|
+
echo "Error: No SHA256 tool available." >&2
|
|
11
13
|
exit 1
|
|
12
14
|
fi
|
|
13
15
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "braidfs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.155",
|
|
4
4
|
"description": "braid technology synchronizing files and webpages",
|
|
5
5
|
"author": "Braid Working Group",
|
|
6
6
|
"repository": "braid-org/braidfs",
|
|
7
7
|
"homepage": "https://braid.org",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"braid-http": "~1.3.89",
|
|
10
|
-
"braid-text": "~0.5.
|
|
11
|
-
"braid-blob": "~0.0.
|
|
10
|
+
"braid-text": "~0.5.20",
|
|
11
|
+
"braid-blob": "~0.0.84",
|
|
12
12
|
"chokidar": "^4.0.3",
|
|
13
13
|
"undici": "^7.18.2"
|
|
14
14
|
},
|