braidfs 0.0.132 → 0.0.133
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 -191
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var { diff_main } = require(`${__dirname}/diff.js`),
|
|
4
4
|
braid_text = require("braid-text"),
|
|
5
|
+
braid_blob = require("braid-blob"),
|
|
5
6
|
braid_fetch = require('braid-http').fetch
|
|
6
7
|
|
|
7
8
|
// Helper function to check if a file is binary based on its extension
|
|
@@ -27,6 +28,8 @@ var braidfs_config_dir = `${sync_base}/.braidfs`,
|
|
|
27
28
|
braidfs_config_file = `${braidfs_config_dir}/config`,
|
|
28
29
|
sync_base_meta = `${braidfs_config_dir}/proxy_base_meta`
|
|
29
30
|
braid_text.db_folder = `${braidfs_config_dir}/braid-text-db`
|
|
31
|
+
braid_blob.db_folder = { read: () => {}, write: () => {}, delete: () => {} }
|
|
32
|
+
braid_blob.meta_folder = `${braidfs_config_dir}/braid-blob-meta`
|
|
30
33
|
var trash = `${braidfs_config_dir}/trash`
|
|
31
34
|
var temp_folder = `${braidfs_config_dir}/temp`
|
|
32
35
|
|
|
@@ -417,6 +420,7 @@ async function sync_url(url) {
|
|
|
417
420
|
url = normalized_url
|
|
418
421
|
|
|
419
422
|
await braid_text.db_folder_init()
|
|
423
|
+
await braid_blob.init()
|
|
420
424
|
|
|
421
425
|
var is_external_link = url.match(/^https?:\/\//),
|
|
422
426
|
path = is_external_link ? url.replace(/^https?:\/\//, '') : url,
|
|
@@ -451,7 +455,10 @@ async function sync_url(url) {
|
|
|
451
455
|
await self.disconnect?.()
|
|
452
456
|
await wait_promise
|
|
453
457
|
|
|
454
|
-
|
|
458
|
+
if (self.merge_type === 'dt')
|
|
459
|
+
await braid_text.delete(url)
|
|
460
|
+
else if (self.merge_type === 'aww')
|
|
461
|
+
await braid_blob.delete(url)
|
|
455
462
|
|
|
456
463
|
try {
|
|
457
464
|
console.log(`trying to delete: ${meta_path}`)
|
|
@@ -520,12 +527,14 @@ async function sync_url(url) {
|
|
|
520
527
|
await require('fs').promises.writeFile(meta_path, JSON.stringify({
|
|
521
528
|
merge_type: self.merge_type,
|
|
522
529
|
peer: self.peer,
|
|
523
|
-
version: self.version,
|
|
524
530
|
file_mtimeNs_str: self.file_mtimeNs_str
|
|
525
531
|
}))
|
|
526
532
|
}
|
|
527
533
|
|
|
528
|
-
|
|
534
|
+
self.file_mtimeNs_str = null
|
|
535
|
+
self.file_read_only = null
|
|
536
|
+
|
|
537
|
+
await within_fiber(fullpath, async () => {
|
|
529
538
|
try {
|
|
530
539
|
Object.assign(self, JSON.parse(
|
|
531
540
|
await require('fs').promises.readFile(meta_path, 'utf8')))
|
|
@@ -533,219 +542,131 @@ async function sync_url(url) {
|
|
|
533
542
|
if (freed) return
|
|
534
543
|
|
|
535
544
|
if (!self.peer) self.peer = Math.random().toString(36).slice(2)
|
|
536
|
-
|
|
537
|
-
// create file if it doesn't exist
|
|
538
|
-
var fullpath = await get_fullpath()
|
|
539
|
-
if (freed) return
|
|
540
|
-
if (!(await file_exists(fullpath))) {
|
|
541
|
-
if (freed) return
|
|
542
|
-
await wait_on(require('fs').promises.writeFile(fullpath, ''))
|
|
543
|
-
if (freed) return
|
|
544
|
-
var stat = await require('fs').promises.stat(fullpath, { bigint: true })
|
|
545
|
-
if (freed) return
|
|
546
|
-
self.file_mtimeNs_str = '' + stat.mtimeNs
|
|
547
|
-
self.last_touch = Date.now()
|
|
548
|
-
}
|
|
549
|
-
if (freed) return
|
|
550
|
-
|
|
551
|
-
await save_meta()
|
|
552
545
|
})
|
|
553
546
|
if (freed) return
|
|
554
547
|
|
|
555
|
-
|
|
556
|
-
|
|
548
|
+
self.signal_file_needs_reading = async () => {
|
|
549
|
+
await within_fiber(fullpath, async () => {
|
|
550
|
+
try {
|
|
551
|
+
if (freed) return
|
|
557
552
|
|
|
558
|
-
|
|
553
|
+
var fullpath = await get_fullpath()
|
|
554
|
+
if (freed) return
|
|
559
555
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
if (freed) return
|
|
563
|
-
if (last_connect_timer) return
|
|
556
|
+
var stat = await require('fs').promises.stat(fullpath, { bigint: true })
|
|
557
|
+
if (freed) return
|
|
564
558
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
if (closed) return
|
|
569
|
-
closed = true
|
|
570
|
-
reconnect_rate_limiter.on_diss(url)
|
|
571
|
-
for (var a of aborts) a.abort()
|
|
572
|
-
aborts.clear()
|
|
573
|
-
}
|
|
574
|
-
self.reconnect = connect
|
|
575
|
-
|
|
576
|
-
await prev_disconnect?.()
|
|
577
|
-
if (freed || closed) return
|
|
578
|
-
|
|
579
|
-
await reconnect_rate_limiter.get_turn(url)
|
|
580
|
-
if (freed || closed) return
|
|
581
|
-
|
|
582
|
-
function retry(e) {
|
|
583
|
-
if (freed || closed) return
|
|
584
|
-
var p = self.disconnect()
|
|
585
|
-
|
|
586
|
-
var delay = waitTime * (config.retry_delay_ms ?? 1000)
|
|
587
|
-
console.log(`reconnecting in ${(delay / 1000).toFixed(2)}s: ${url} after error: ${e}`)
|
|
588
|
-
last_connect_timer = setTimeout(async () => {
|
|
589
|
-
await p
|
|
590
|
-
last_connect_timer = null
|
|
591
|
-
connect()
|
|
592
|
-
}, delay)
|
|
593
|
-
waitTime = Math.min(waitTime + 1, 3)
|
|
594
|
-
}
|
|
559
|
+
if (self.file_mtimeNs_str !== '' + stat.mtimeNs) {
|
|
560
|
+
var data = await require('fs').promises.readFile(fullpath, { encoding: 'utf8' })
|
|
561
|
+
if (freed) return
|
|
595
562
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
signal: a.signal,
|
|
605
|
-
method: "HEAD",
|
|
606
|
-
version: ['' + self.version]
|
|
607
|
-
})
|
|
608
|
-
if (r.ok) fork_point = ['' + self.version]
|
|
563
|
+
await braid_blob.put(url, data, { skip_write: true })
|
|
564
|
+
if (freed) return
|
|
565
|
+
|
|
566
|
+
self.file_mtimeNs_str = '' + stat.mtimeNs
|
|
567
|
+
await save_meta()
|
|
568
|
+
}
|
|
569
|
+
} catch (e) {
|
|
570
|
+
if (e.code !== 'ENOENT') throw e
|
|
609
571
|
}
|
|
572
|
+
})
|
|
573
|
+
}
|
|
574
|
+
await self.signal_file_needs_reading()
|
|
610
575
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
subscribe: true,
|
|
617
|
-
heartbeats: 120,
|
|
618
|
-
peer: self.peer,
|
|
619
|
-
parents: fork_point || []
|
|
620
|
-
})
|
|
621
|
-
if (freed || closed) return
|
|
622
|
-
|
|
623
|
-
if (res.status < 200 || res.status >= 300) return retry(new Error(`unexpected status: ${res.status}`))
|
|
624
|
-
|
|
625
|
-
if (res.status !== 209)
|
|
626
|
-
return log_error(`Can't sync ${url} -- got bad response ${res.status} from server (expected 209)`)
|
|
627
|
-
|
|
628
|
-
self.file_read_only = res.headers.get('editable') === 'false'
|
|
576
|
+
var db = {
|
|
577
|
+
read: async (_key) => {
|
|
578
|
+
return await within_fiber(fullpath, async () => {
|
|
579
|
+
var fullpath = await get_fullpath()
|
|
580
|
+
if (freed) return
|
|
629
581
|
|
|
630
|
-
|
|
582
|
+
try {
|
|
583
|
+
return await require('fs').promises.readFile(fullpath)
|
|
584
|
+
} catch (e) {
|
|
585
|
+
if (e.code === 'ENOENT') return null
|
|
586
|
+
throw e
|
|
587
|
+
}
|
|
588
|
+
})
|
|
589
|
+
},
|
|
590
|
+
write: async (_key, data) => {
|
|
591
|
+
return await within_fiber(fullpath, async () => {
|
|
631
592
|
var fullpath = await get_fullpath()
|
|
632
|
-
if (freed
|
|
593
|
+
if (freed) return
|
|
633
594
|
|
|
634
|
-
|
|
635
|
-
|
|
595
|
+
try {
|
|
596
|
+
var temp = `${temp_folder}/${Math.random().toString(36).slice(2)}`
|
|
597
|
+
await require('fs').promises.writeFile(temp, data)
|
|
598
|
+
if (freed) return
|
|
636
599
|
|
|
637
|
-
|
|
600
|
+
var stat = await require('fs').promises.stat(temp, { bigint: true })
|
|
601
|
+
if (freed) return
|
|
638
602
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
res.subscribe(async update => {
|
|
642
|
-
if (freed || closed) return
|
|
643
|
-
if (update.version.length === 0) return
|
|
644
|
-
if (update.version.length !== 1) throw 'unexpected'
|
|
645
|
-
var version = 1*update.version[0]
|
|
646
|
-
if (!update.body) return
|
|
647
|
-
|
|
648
|
-
if (self.version != null &&
|
|
649
|
-
version <= self.version) return
|
|
650
|
-
self.version = version
|
|
651
|
-
|
|
652
|
-
await within_fiber(url, async () => {
|
|
653
|
-
var fullpath = await get_fullpath()
|
|
654
|
-
if (freed || closed) return
|
|
655
|
-
|
|
656
|
-
await wait_on(set_read_only(fullpath, false))
|
|
657
|
-
if (freed || closed) return
|
|
658
|
-
await wait_on(require('fs').promises.writeFile(fullpath, update.body))
|
|
659
|
-
if (freed || closed) return
|
|
660
|
-
await wait_on(set_read_only(fullpath, self.file_read_only))
|
|
661
|
-
if (freed || closed) return
|
|
662
|
-
|
|
663
|
-
var stat = await require('fs').promises.stat(fullpath, { bigint: true })
|
|
664
|
-
if (freed || closed) return
|
|
665
|
-
self.file_mtimeNs_str = '' + stat.mtimeNs
|
|
666
|
-
self.last_touch = Date.now()
|
|
603
|
+
await require('fs').promises.rename(temp, fullpath)
|
|
604
|
+
if (freed) return
|
|
667
605
|
|
|
606
|
+
self.file_mtimeNs_str = '' + stat.mtimeNs
|
|
668
607
|
await save_meta()
|
|
669
|
-
})
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
var a = new AbortController()
|
|
678
|
-
aborts.add(a)
|
|
679
|
-
var r = await braid_fetch(url, {
|
|
680
|
-
method: 'PUT',
|
|
681
|
-
signal: a.signal,
|
|
682
|
-
version: ['' + self.version],
|
|
683
|
-
body,
|
|
684
|
-
headers: {
|
|
685
|
-
...(x => x && {Cookie: x})(config.cookies?.[new URL(url).hostname])
|
|
686
|
-
},
|
|
687
|
-
})
|
|
688
|
-
if (freed || closed) return
|
|
689
|
-
|
|
690
|
-
// if we're not authorized,
|
|
691
|
-
if (r.status == 401 || r.status == 403) {
|
|
692
|
-
// then revert it
|
|
693
|
-
console.log(`access denied: reverting local edits`)
|
|
694
|
-
unsync_url(url)
|
|
695
|
-
sync_url(url)
|
|
696
|
-
} else if (!r.ok) {
|
|
697
|
-
retry(new Error(`unexpected PUT status: ${r.status}`))
|
|
698
|
-
}
|
|
699
|
-
} catch (e) { retry(e) }
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
// if what we have now is newer than what the server has,
|
|
703
|
-
// go ahead and send it
|
|
704
|
-
await within_fiber(url, async () => {
|
|
705
|
-
if (freed || closed) return
|
|
608
|
+
} catch (e) {
|
|
609
|
+
if (e.code === 'ENOENT') return null
|
|
610
|
+
throw e
|
|
611
|
+
}
|
|
612
|
+
})
|
|
613
|
+
},
|
|
614
|
+
delete: async (_key) => {
|
|
615
|
+
return await within_fiber(fullpath, async () => {
|
|
706
616
|
var fullpath = await get_fullpath()
|
|
707
|
-
if (freed
|
|
617
|
+
if (freed) return
|
|
618
|
+
|
|
708
619
|
try {
|
|
709
|
-
|
|
710
|
-
} catch (e) {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
var server_v = JSON.parse(`[${res.headers.get('current-version')}]`)
|
|
714
|
-
if (self.version != null &&
|
|
715
|
-
'' + stat.mtimeNs === self.file_mtimeNs_str && (
|
|
716
|
-
!server_v.length ||
|
|
717
|
-
1*server_v[0] < self.version
|
|
718
|
-
)) await send_file(fullpath)
|
|
620
|
+
await require('fs').promises.unlink(fullpath)
|
|
621
|
+
} catch (e) {
|
|
622
|
+
if (e.code !== 'ENOENT') throw e
|
|
623
|
+
}
|
|
719
624
|
})
|
|
625
|
+
}
|
|
626
|
+
}
|
|
720
627
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
var fullpath = await get_fullpath()
|
|
726
|
-
if (freed || closed) return
|
|
727
|
-
|
|
728
|
-
try {
|
|
729
|
-
var stat = await require('fs').promises.stat(fullpath, { bigint: true })
|
|
730
|
-
} catch (e) { return }
|
|
731
|
-
if (freed || closed) return
|
|
628
|
+
var ac
|
|
629
|
+
function start_sync() {
|
|
630
|
+
if (ac) ac.abort()
|
|
631
|
+
if (freed) return
|
|
732
632
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
Math.round(Number(stat.mtimeNs) / 1000000))
|
|
633
|
+
var closed = false
|
|
634
|
+
ac = new AbortController()
|
|
736
635
|
|
|
737
|
-
|
|
738
|
-
|
|
636
|
+
self.disconnect = async () => {
|
|
637
|
+
if (closed) return
|
|
638
|
+
closed = true
|
|
639
|
+
reconnect_rate_limiter.on_diss(url)
|
|
640
|
+
ac.abort()
|
|
641
|
+
}
|
|
739
642
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
643
|
+
braid_blob.sync(url, new URL(url), {
|
|
644
|
+
db,
|
|
645
|
+
signal: ac.signal,
|
|
646
|
+
peer: self.peer,
|
|
647
|
+
headers: {
|
|
648
|
+
'Content-Type': 'text/plain',
|
|
649
|
+
...(x => x && { Cookie: x })(config.cookies?.[new URL(url).hostname])
|
|
650
|
+
},
|
|
651
|
+
on_pre_connect: () => reconnect_rate_limiter.get_turn(url),
|
|
652
|
+
on_res: res => {
|
|
653
|
+
if (freed) return
|
|
654
|
+
reconnect_rate_limiter.on_conn(url)
|
|
655
|
+
self.file_read_only = res.headers.get('editable') === 'false'
|
|
656
|
+
console.log(`connected to ${url}${self.file_read_only ? ' (readonly)' : ''}`)
|
|
657
|
+
},
|
|
658
|
+
on_unauthorized: async () => {
|
|
659
|
+
console.log(`access denied: reverting local edits`)
|
|
660
|
+
unsync_url(url)
|
|
661
|
+
sync_url(url)
|
|
662
|
+
},
|
|
663
|
+
on_disconnect: () => reconnect_rate_limiter.on_diss(url)
|
|
664
|
+
})
|
|
747
665
|
}
|
|
748
666
|
|
|
667
|
+
self.reconnect = () => start_sync()
|
|
668
|
+
|
|
669
|
+
start_sync()
|
|
749
670
|
return self
|
|
750
671
|
}
|
|
751
672
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "braidfs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.133",
|
|
4
4
|
"description": "braid technology synchronizing files and webpages",
|
|
5
5
|
"author": "Braid Working Group",
|
|
6
6
|
"repository": "braid-org/braidfs",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"braid-http": "~1.3.85",
|
|
10
10
|
"braid-text": "~0.2.97",
|
|
11
|
-
"braid-blob": "~0.0.
|
|
11
|
+
"braid-blob": "~0.0.42",
|
|
12
12
|
"chokidar": "^4.0.3"
|
|
13
13
|
},
|
|
14
14
|
"bin": {
|