braidfs 0.0.94 → 0.0.96
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 +234 -224
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -378,7 +378,8 @@ async function sync_url(url) {
|
|
|
378
378
|
if (!sync_url.cache) sync_url.cache = {}
|
|
379
379
|
if (!sync_url.chain) sync_url.chain = Promise.resolve()
|
|
380
380
|
if (!sync_url.cache[path]) {
|
|
381
|
-
var
|
|
381
|
+
var self = {url},
|
|
382
|
+
freed = false,
|
|
382
383
|
aborts = new Set(),
|
|
383
384
|
braid_text_get_options = null
|
|
384
385
|
var wait_promise = Promise.resolve()
|
|
@@ -398,9 +399,8 @@ async function sync_url(url) {
|
|
|
398
399
|
if (!unsync_url.cache) unsync_url.cache = {}
|
|
399
400
|
unsync_url.cache[path] = async () => {
|
|
400
401
|
freed = true
|
|
401
|
-
|
|
402
|
+
await self.disconnect?.()
|
|
402
403
|
await wait_promise
|
|
403
|
-
if (braid_text_get_options) await braid_text.forget(url, braid_text_get_options)
|
|
404
404
|
|
|
405
405
|
delete braid_text.cache[url]
|
|
406
406
|
for (let f of await braid_text.get_files_for_key(url)) {
|
|
@@ -416,8 +416,6 @@ async function sync_url(url) {
|
|
|
416
416
|
async function init() {
|
|
417
417
|
if (freed) return
|
|
418
418
|
|
|
419
|
-
var self = {url}
|
|
420
|
-
|
|
421
419
|
console.log(`sync_url: ${url}`)
|
|
422
420
|
|
|
423
421
|
var resource = await braid_text.get_resource(url)
|
|
@@ -489,55 +487,6 @@ async function sync_url(url) {
|
|
|
489
487
|
file_loop_pump()
|
|
490
488
|
}
|
|
491
489
|
|
|
492
|
-
async function my_fetch(params) {
|
|
493
|
-
if (freed) return
|
|
494
|
-
try {
|
|
495
|
-
var a = new AbortController()
|
|
496
|
-
aborts.add(a)
|
|
497
|
-
return await braid_fetch(url, {
|
|
498
|
-
signal: a.signal,
|
|
499
|
-
headers: {
|
|
500
|
-
"Merge-Type": "dt",
|
|
501
|
-
"Content-Type": 'text/plain',
|
|
502
|
-
...(x => x && {Cookie: x})(config.cookies?.[new URL(url).hostname])
|
|
503
|
-
},
|
|
504
|
-
retry: { retryRes: r => r.status !== 401 && r.status !== 403 },
|
|
505
|
-
...params
|
|
506
|
-
})
|
|
507
|
-
} catch (e) {
|
|
508
|
-
if (freed) return
|
|
509
|
-
if (e?.name !== "AbortError") console.log(e)
|
|
510
|
-
} finally {
|
|
511
|
-
if (freed) return
|
|
512
|
-
aborts.delete(a)
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
async function send_out(stuff) {
|
|
517
|
-
if (!is_external_link) return
|
|
518
|
-
if (freed) return
|
|
519
|
-
|
|
520
|
-
console.log(`send_out ${url} ${JSON.stringify(stuff, null, 4).slice(0, 1000)}`)
|
|
521
|
-
|
|
522
|
-
var r = await my_fetch({ method: "PUT", ...stuff })
|
|
523
|
-
if (freed) return
|
|
524
|
-
|
|
525
|
-
// the server has acknowledged this version,
|
|
526
|
-
// so add it to the fork point
|
|
527
|
-
if (r.ok) self.update_fork_point(stuff.version[0], stuff.parents)
|
|
528
|
-
|
|
529
|
-
// if we're not authorized,
|
|
530
|
-
if (r.status == 401 || r.status == 403) {
|
|
531
|
-
// and it's one of our versions (a local edit),
|
|
532
|
-
if (self.peer === braid_text.decode_version(stuff.version[0])[0]) {
|
|
533
|
-
// then revert it
|
|
534
|
-
console.log(`access denied: reverting local edits`)
|
|
535
|
-
unsync_url(url)
|
|
536
|
-
sync_url(url)
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
490
|
await within_fiber(fullpath, async () => {
|
|
542
491
|
if (freed) return
|
|
543
492
|
var fullpath = await get_fullpath()
|
|
@@ -776,193 +725,254 @@ async function sync_url(url) {
|
|
|
776
725
|
return frontier.sort()
|
|
777
726
|
}
|
|
778
727
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
console.log(`[find_fork_point] url: ${url}`)
|
|
728
|
+
var waitTime = 1
|
|
729
|
+
var last_connect_timer = null
|
|
782
730
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
731
|
+
if (is_external_link) connect()
|
|
732
|
+
async function connect() {
|
|
733
|
+
if (freed) return
|
|
734
|
+
if (last_connect_timer) return
|
|
735
|
+
|
|
736
|
+
var closed = false
|
|
737
|
+
var prev_disconnect = self.disconnect
|
|
738
|
+
self.disconnect = async () => {
|
|
739
|
+
if (closed) return
|
|
740
|
+
closed = true
|
|
741
|
+
for (var a of aborts) a.abort()
|
|
742
|
+
aborts.clear()
|
|
743
|
+
if (braid_text_get_options) await braid_text.forget(url, braid_text_get_options)
|
|
744
|
+
braid_text_get_options = null
|
|
791
745
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
var r = await my_fetch({ method: "HEAD", version })
|
|
809
|
-
if (freed) return
|
|
810
|
-
console.log(`fetched in ${Date.now() - st}`)
|
|
811
|
-
|
|
812
|
-
if (r.ok) {
|
|
813
|
-
min = i
|
|
814
|
-
self.fork_point = version
|
|
815
|
-
} else max = i
|
|
746
|
+
self.reconnect = connect
|
|
747
|
+
|
|
748
|
+
await prev_disconnect?.()
|
|
749
|
+
if (freed || closed) return
|
|
750
|
+
|
|
751
|
+
async function retry(e) {
|
|
752
|
+
if (freed || closed) return
|
|
753
|
+
var p = self.disconnect()
|
|
754
|
+
|
|
755
|
+
console.log(`reconnecting in ${waitTime}s: ${url} after error: ${e}`)
|
|
756
|
+
last_connect_timer = setTimeout(async () => {
|
|
757
|
+
await p
|
|
758
|
+
last_connect_timer = null
|
|
759
|
+
connect()
|
|
760
|
+
}, waitTime * 1000)
|
|
761
|
+
waitTime = Math.min(waitTime + 1, 3)
|
|
816
762
|
}
|
|
817
|
-
console.log(`[find_fork_point] settled on: ${JSON.stringify(self.fork_point)}`)
|
|
818
|
-
self.signal_file_needs_writing(true)
|
|
819
|
-
return self.fork_point
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
var initial_connect_done
|
|
823
|
-
var initial_connect_promise = new Promise(done => initial_connect_done = done)
|
|
824
763
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
await send_new_stuff(fork_point)
|
|
828
|
-
if (freed) return
|
|
829
|
-
connect(fork_point)
|
|
830
|
-
})
|
|
831
|
-
|
|
832
|
-
function connect(fork_point) {
|
|
833
|
-
if (freed) return
|
|
834
|
-
let a = new AbortController()
|
|
835
|
-
aborts.add(a)
|
|
836
|
-
self.reconnect = () => {
|
|
837
|
-
if (freed) return
|
|
838
|
-
console.log(`reconnecting ${url}`)
|
|
764
|
+
var initial_connect_done
|
|
765
|
+
var initial_connect_promise = new Promise(done => initial_connect_done = done)
|
|
839
766
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
767
|
+
async function my_fetch(params) {
|
|
768
|
+
if (freed || closed) return
|
|
769
|
+
try {
|
|
770
|
+
var a = new AbortController()
|
|
771
|
+
aborts.add(a)
|
|
772
|
+
return await braid_fetch(url, {
|
|
773
|
+
signal: a.signal,
|
|
774
|
+
headers: {
|
|
775
|
+
"Merge-Type": "dt",
|
|
776
|
+
"Content-Type": 'text/plain',
|
|
777
|
+
...(x => x && {Cookie: x})(config.cookies?.[new URL(url).hostname])
|
|
778
|
+
},
|
|
779
|
+
retry: { retryRes: r => r.status !== 401 && r.status !== 403 },
|
|
780
|
+
...params
|
|
781
|
+
})
|
|
782
|
+
} catch (e) {
|
|
783
|
+
if (freed || closed) return
|
|
784
|
+
if (e?.name !== "AbortError") console.log(e)
|
|
785
|
+
} finally {
|
|
786
|
+
if (freed || closed) return
|
|
787
|
+
aborts.delete(a)
|
|
788
|
+
}
|
|
843
789
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
790
|
+
|
|
791
|
+
async function send_out(stuff) {
|
|
792
|
+
if (freed || closed) return
|
|
793
|
+
|
|
794
|
+
console.log(`send_out ${url} ${JSON.stringify(stuff, null, 4).slice(0, 1000)}`)
|
|
795
|
+
|
|
796
|
+
var r = await my_fetch({ method: "PUT", ...stuff })
|
|
797
|
+
if (freed || closed) return
|
|
798
|
+
|
|
799
|
+
// the server has acknowledged this version,
|
|
800
|
+
// so add it to the fork point
|
|
801
|
+
if (r.ok) self.update_fork_point(stuff.version[0], stuff.parents)
|
|
802
|
+
|
|
803
|
+
// if we're not authorized,
|
|
804
|
+
if (r.status == 401 || r.status == 403) {
|
|
805
|
+
// and it's one of our versions (a local edit),
|
|
806
|
+
if (self.peer === braid_text.decode_version(stuff.version[0])[0]) {
|
|
807
|
+
// then revert it
|
|
808
|
+
console.log(`access denied: reverting local edits`)
|
|
809
|
+
unsync_url(url)
|
|
810
|
+
sync_url(url)
|
|
865
811
|
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
parents: async () => {
|
|
869
|
-
if (freed) return
|
|
870
|
-
var x = fork_point || await find_fork_point()
|
|
871
|
-
if (freed) return
|
|
872
|
-
fork_point = null
|
|
873
|
-
return x
|
|
874
|
-
},
|
|
875
|
-
peer: self.peer
|
|
876
|
-
}).then(x => {
|
|
877
|
-
if (freed) return
|
|
878
|
-
if (x.status !== 209) throw new Error(`unexpected status: ${x.status}`)
|
|
879
|
-
initial_connect_done()
|
|
880
|
-
x.subscribe(async update => {
|
|
881
|
-
if (freed) return
|
|
882
|
-
console.log(`got external update about ${url}`)
|
|
812
|
+
}
|
|
813
|
+
}
|
|
883
814
|
|
|
884
|
-
|
|
885
|
-
|
|
815
|
+
async function find_fork_point() {
|
|
816
|
+
if (freed || closed) return
|
|
817
|
+
console.log(`[find_fork_point] url: ${url}`)
|
|
886
818
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
819
|
+
// see if remote has the fork point
|
|
820
|
+
if (self.fork_point) {
|
|
821
|
+
var r = await my_fetch({ method: "HEAD", version: self.fork_point })
|
|
822
|
+
if (freed || closed) return
|
|
823
|
+
if (r.ok) return console.log(`[find_fork_point] it has our latest fork point, hooray!`)
|
|
824
|
+
}
|
|
890
825
|
|
|
891
|
-
|
|
892
|
-
|
|
826
|
+
// otherwise let's binary search for new fork point..
|
|
827
|
+
var bytes = resource.doc.toBytes()
|
|
828
|
+
var [_, events, __] = braid_text.dt_parse([...bytes])
|
|
829
|
+
events = events.map(x => x.join('-'))
|
|
830
|
+
|
|
831
|
+
var min = -1
|
|
832
|
+
var max = events.length
|
|
833
|
+
self.fork_point = []
|
|
834
|
+
while (min + 1 < max) {
|
|
835
|
+
var i = Math.floor((min + max)/2)
|
|
836
|
+
var version = [events[i]]
|
|
837
|
+
|
|
838
|
+
console.log(`min=${min}, max=${max}, i=${i}, version=${version}`)
|
|
839
|
+
|
|
840
|
+
var st = Date.now()
|
|
841
|
+
var r = await my_fetch({ method: "HEAD", version })
|
|
842
|
+
if (freed || closed) return
|
|
843
|
+
console.log(`fetched in ${Date.now() - st}`)
|
|
844
|
+
|
|
845
|
+
if (r.ok) {
|
|
846
|
+
min = i
|
|
847
|
+
self.fork_point = version
|
|
848
|
+
} else max = i
|
|
849
|
+
}
|
|
850
|
+
console.log(`[find_fork_point] settled on: ${JSON.stringify(self.fork_point)}`)
|
|
851
|
+
self.signal_file_needs_writing(true)
|
|
852
|
+
}
|
|
893
853
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
// so let's add it to our fork point
|
|
897
|
-
self.update_fork_point(update.version[0], update.parents)
|
|
854
|
+
await find_fork_point()
|
|
855
|
+
if (freed || closed) return
|
|
898
856
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
}).catch(e => (e?.name !== "AbortError") && console.log(e))
|
|
902
|
-
}
|
|
857
|
+
await send_new_stuff()
|
|
858
|
+
if (freed || closed) return
|
|
903
859
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
860
|
+
console.log(`connecting to ${url}`)
|
|
861
|
+
let a = new AbortController()
|
|
862
|
+
aborts.add(a)
|
|
863
|
+
try {
|
|
864
|
+
var res = await braid_fetch(url, {
|
|
865
|
+
signal: a.signal,
|
|
866
|
+
headers: {
|
|
867
|
+
"Merge-Type": "dt",
|
|
868
|
+
Accept: 'text/plain',
|
|
869
|
+
...(x => x && {Cookie: x})(config.cookies?.[new URL(url).hostname]),
|
|
870
|
+
},
|
|
871
|
+
subscribe: true,
|
|
872
|
+
heartbeats: 120,
|
|
873
|
+
parents: self.fork_point,
|
|
874
|
+
peer: self.peer
|
|
875
|
+
})
|
|
876
|
+
} catch (e) { return retry(e) }
|
|
877
|
+
if (freed || closed) return
|
|
878
|
+
|
|
879
|
+
if (res.status < 200 || res.status >= 300) return retry(new Error(`unexpected status: ${res.status}`))
|
|
880
|
+
|
|
881
|
+
if (res.status !== 209)
|
|
882
|
+
return log_error(`Can't sync ${url} -- got bad response ${res.status} from server (expected 209)`)
|
|
883
|
+
|
|
884
|
+
console.log(`connected to ${url}`)
|
|
885
|
+
console.log(` editable = ${res.headers.get('editable')}`)
|
|
886
|
+
|
|
887
|
+
self.file_read_only = res.headers.get('editable') === 'false'
|
|
888
|
+
self.signal_file_needs_writing()
|
|
889
|
+
|
|
890
|
+
initial_connect_done()
|
|
891
|
+
res.subscribe(async update => {
|
|
892
|
+
if (freed || closed) return
|
|
893
|
+
console.log(`got external update about ${url}`)
|
|
894
|
+
|
|
895
|
+
if (update.body) update.body = update.body_text
|
|
896
|
+
if (update.patches) for (let p of update.patches) p.content = p.content_text
|
|
897
|
+
|
|
898
|
+
// console.log(`update: ${JSON.stringify(update, null, 4)}`)
|
|
899
|
+
if (update.version.length === 0) return
|
|
900
|
+
if (update.version.length !== 1) throw 'unexpected'
|
|
901
|
+
|
|
902
|
+
await wait_on(braid_text.put(url, { ...update, peer: self.peer, merge_type: 'dt' }))
|
|
903
|
+
if (freed || closed) return
|
|
904
|
+
|
|
905
|
+
// the server is giving us this version,
|
|
906
|
+
// so it must have it,
|
|
907
|
+
// so let's add it to our fork point
|
|
908
|
+
self.update_fork_point(update.version[0], update.parents)
|
|
909
|
+
|
|
910
|
+
self.signal_file_needs_writing()
|
|
911
|
+
}, retry)
|
|
912
|
+
|
|
913
|
+
// send it stuff we have but it doesn't't
|
|
914
|
+
async function send_new_stuff() {
|
|
915
|
+
if (freed || closed) return
|
|
916
|
+
var q = []
|
|
917
|
+
var in_flight = new Map()
|
|
918
|
+
var max_in_flight = 10
|
|
919
|
+
var send_pump_lock = 0
|
|
920
|
+
|
|
921
|
+
async function send_pump() {
|
|
922
|
+
send_pump_lock++
|
|
923
|
+
if (send_pump_lock > 1) return
|
|
924
|
+
try {
|
|
925
|
+
if (freed || closed) return
|
|
926
|
+
if (in_flight.size >= max_in_flight) return
|
|
927
|
+
if (!q.length) {
|
|
928
|
+
var frontier = self.fork_point
|
|
929
|
+
for (var u of in_flight.values())
|
|
930
|
+
frontier = extend_frontier(frontier, u.version[0], u.parents)
|
|
931
|
+
|
|
932
|
+
var options = {
|
|
933
|
+
parents: frontier,
|
|
934
|
+
merge_type: 'dt',
|
|
935
|
+
peer: self.peer,
|
|
936
|
+
subscribe: u => u.version.length && q.push(u)
|
|
937
|
+
}
|
|
938
|
+
await braid_text.get(url, options)
|
|
939
|
+
await braid_text.forget(url, options)
|
|
928
940
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
941
|
+
while (q.length && in_flight.size < max_in_flight) {
|
|
942
|
+
let u = q.shift()
|
|
943
|
+
in_flight.set(u.version[0], u);
|
|
944
|
+
(async () => {
|
|
945
|
+
await initial_connect_promise
|
|
946
|
+
if (freed || closed) return
|
|
947
|
+
await send_out({...u, peer: self.peer})
|
|
948
|
+
if (freed || closed) return
|
|
949
|
+
in_flight.delete(u.version[0])
|
|
950
|
+
setTimeout(send_pump, 0)
|
|
951
|
+
})()
|
|
952
|
+
}
|
|
953
|
+
} finally {
|
|
954
|
+
var retry = send_pump_lock > 1
|
|
955
|
+
send_pump_lock = 0
|
|
956
|
+
if (retry) setTimeout(send_pump, 0)
|
|
943
957
|
}
|
|
944
|
-
} finally {
|
|
945
|
-
var retry = send_pump_lock > 1
|
|
946
|
-
send_pump_lock = 0
|
|
947
|
-
if (retry) setTimeout(send_pump, 0)
|
|
948
958
|
}
|
|
949
|
-
}
|
|
950
959
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
960
|
+
var initial_stuff = true
|
|
961
|
+
await wait_on(braid_text.get(url, braid_text_get_options = {
|
|
962
|
+
parents: self.fork_point,
|
|
963
|
+
merge_type: 'dt',
|
|
964
|
+
peer: self.peer,
|
|
965
|
+
subscribe: async (u) => {
|
|
966
|
+
if (freed || closed) return
|
|
967
|
+
if (u.version.length) {
|
|
968
|
+
self.signal_file_needs_writing()
|
|
969
|
+
if (initial_stuff || in_flight.size < max_in_flight) q.push(u)
|
|
970
|
+
send_pump()
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
|
+
}))
|
|
974
|
+
initial_stuff = false
|
|
975
|
+
}
|
|
966
976
|
}
|
|
967
977
|
|
|
968
978
|
// for config and errors file, listen for web changes
|