braidfs 0.0.95 → 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.
Files changed (2) hide show
  1. package/index.js +232 -222
  2. 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 freed = false,
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
- for (let a of aborts) a.abort()
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)
@@ -727,242 +725,254 @@ async function sync_url(url) {
727
725
  return frontier.sort()
728
726
  }
729
727
 
730
- async function my_fetch(params) {
731
- if (freed) return
732
- try {
733
- var a = new AbortController()
734
- aborts.add(a)
735
- return await braid_fetch(url, {
736
- signal: a.signal,
737
- headers: {
738
- "Merge-Type": "dt",
739
- "Content-Type": 'text/plain',
740
- ...(x => x && {Cookie: x})(config.cookies?.[new URL(url).hostname])
741
- },
742
- retry: { retryRes: r => r.status !== 401 && r.status !== 403 },
743
- ...params
744
- })
745
- } catch (e) {
746
- if (freed) return
747
- if (e?.name !== "AbortError") console.log(e)
748
- } finally {
749
- if (freed) return
750
- aborts.delete(a)
751
- }
752
- }
753
-
754
- async function send_out(stuff) {
755
- if (!is_external_link) return
756
- if (freed) return
757
-
758
- console.log(`send_out ${url} ${JSON.stringify(stuff, null, 4).slice(0, 1000)}`)
728
+ var waitTime = 1
729
+ var last_connect_timer = null
759
730
 
760
- var r = await my_fetch({ method: "PUT", ...stuff })
731
+ if (is_external_link) connect()
732
+ async function connect() {
761
733
  if (freed) return
762
-
763
- // the server has acknowledged this version,
764
- // so add it to the fork point
765
- if (r.ok) self.update_fork_point(stuff.version[0], stuff.parents)
766
-
767
- // if we're not authorized,
768
- if (r.status == 401 || r.status == 403) {
769
- // and it's one of our versions (a local edit),
770
- if (self.peer === braid_text.decode_version(stuff.version[0])[0]) {
771
- // then revert it
772
- console.log(`access denied: reverting local edits`)
773
- unsync_url(url)
774
- sync_url(url)
775
- }
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
745
+ }
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)
776
762
  }
777
- }
778
763
 
779
- async function find_fork_point() {
780
- if (freed) return
781
- console.log(`[find_fork_point] url: ${url}`)
764
+ var initial_connect_done
765
+ var initial_connect_promise = new Promise(done => initial_connect_done = done)
782
766
 
783
- // see if remote has the fork point
784
- if (self.fork_point) {
785
- var r = await my_fetch({ method: "HEAD", version: self.fork_point })
786
- if (freed) return
787
- if (r.ok) {
788
- console.log(`[find_fork_point] it has our latest fork point, hooray!`)
789
- return self.fork_point
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)
790
788
  }
791
789
  }
792
-
793
- // otherwise let's binary search for new fork point..
794
- var bytes = resource.doc.toBytes()
795
- var [_, events, __] = braid_text.dt_parse([...bytes])
796
- events = events.map(x => x.join('-'))
797
-
798
- var min = -1
799
- var max = events.length
800
- self.fork_point = []
801
- while (min + 1 < max) {
802
- var i = Math.floor((min + max)/2)
803
- var version = [events[i]]
804
-
805
- console.log(`min=${min}, max=${max}, i=${i}, version=${version}`)
806
-
807
- var st = Date.now()
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
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)
811
+ }
812
+ }
816
813
  }
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
814
 
822
- var initial_connect_done
823
- var initial_connect_promise = new Promise(done => initial_connect_done = done)
815
+ async function find_fork_point() {
816
+ if (freed || closed) return
817
+ console.log(`[find_fork_point] url: ${url}`)
824
818
 
825
- if (is_external_link) find_fork_point().then(async fork_point => {
826
- if (freed) return
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}`)
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
+ }
839
825
 
840
- aborts.delete(a)
841
- a.abort()
842
- connect(fork_point)
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)
843
852
  }
844
853
 
845
- console.log(`connecting to ${url}`)
846
- braid_fetch(url, {
847
- signal: a.signal,
848
- headers: {
849
- "Merge-Type": "dt",
850
- Accept: 'text/plain',
851
- ...(x => x && {Cookie: x})(config.cookies?.[new URL(url).hostname]),
852
- },
853
- subscribe: true,
854
- retry: {
855
- retryRes: () => true,
856
- onRes: (res) => {
857
- if (res.status !== 209)
858
- return log_error(`Can't sync ${url} -- got bad response ${res.status} from server (expected 209)`)
859
-
860
- console.log(`connected to ${url}`)
861
- console.log(` editable = ${res.headers.get('editable')}`)
862
-
863
- self.file_read_only = res.headers.get('editable') === 'false'
864
- self.signal_file_needs_writing()
865
- }
866
- },
867
- heartbeats: 120,
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}`)
883
-
884
- if (update.body) update.body = update.body_text
885
- if (update.patches) for (let p of update.patches) p.content = p.content_text
886
-
887
- // console.log(`update: ${JSON.stringify(update, null, 4)}`)
888
- if (update.version.length === 0) return
889
- if (update.version.length !== 1) throw 'unexpected'
854
+ await find_fork_point()
855
+ if (freed || closed) return
890
856
 
891
- await wait_on(braid_text.put(url, { ...update, peer: self.peer, merge_type: 'dt' }))
892
- if (freed) return
857
+ await send_new_stuff()
858
+ if (freed || closed) return
893
859
 
894
- // the server is giving us this version,
895
- // so it must have it,
896
- // so let's add it to our fork point
897
- self.update_fork_point(update.version[0], update.parents)
898
-
899
- self.signal_file_needs_writing()
900
- }, e => (e?.name !== "AbortError") && console.log(e))
901
- }).catch(e => (e?.name !== "AbortError") && console.log(e))
902
- }
903
-
904
- // send it stuff we have but it doesn't't
905
- async function send_new_stuff(fork_point) {
906
- if (freed) return
907
- var q = []
908
- var in_flight = new Map()
909
- var max_in_flight = 10
910
- var send_pump_lock = 0
911
-
912
- async function send_pump() {
913
- send_pump_lock++
914
- if (send_pump_lock > 1) return
915
- try {
916
- if (freed) return
917
- if (in_flight.size >= max_in_flight) return
918
- if (!q.length) {
919
- var frontier = self.fork_point
920
- for (var u of in_flight.values())
921
- frontier = extend_frontier(frontier, u.version[0], u.parents)
922
-
923
- var options = {
924
- parents: frontier,
925
- merge_type: 'dt',
926
- peer: self.peer,
927
- subscribe: u => u.version.length && q.push(u)
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
- await braid_text.get(url, options)
930
- await braid_text.forget(url, options)
931
- }
932
- while (q.length && in_flight.size < max_in_flight) {
933
- let u = q.shift()
934
- in_flight.set(u.version[0], u);
935
- (async () => {
936
- await initial_connect_promise
937
- if (freed) return
938
- await send_out({...u, peer: self.peer})
939
- if (freed) return
940
- in_flight.delete(u.version[0])
941
- setTimeout(send_pump, 0)
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
- var initial_stuff = true
952
- await wait_on(braid_text.get(url, braid_text_get_options = {
953
- parents: fork_point,
954
- merge_type: 'dt',
955
- peer: self.peer,
956
- subscribe: async (u) => {
957
- if (freed) return
958
- if (u.version.length) {
959
- self.signal_file_needs_writing()
960
- if (initial_stuff || in_flight.size < max_in_flight) q.push(u)
961
- send_pump()
962
- }
963
- },
964
- }))
965
- initial_stuff = false
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braidfs",
3
- "version": "0.0.95",
3
+ "version": "0.0.96",
4
4
  "description": "braid technology synchronizing files and webpages",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braidfs",