mirror of
https://github.com/urbit/shrub.git
synced 2024-12-26 05:23:35 +03:00
Merge branch 'release/next-js' into la/release-2021-03-04
This commit is contained in:
commit
b2759b9f36
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9812a52d34be0d6d47ca60b23d3386e7db296ff61fac7c4b1f33a35806f8cb7c
|
oid sha256:ec80a42446a1d80974f32bf87283435547441cb7ea3fcd340711df2ce6cbec81
|
||||||
size 9751012
|
size 9146390
|
||||||
|
@ -593,10 +593,10 @@
|
|||||||
%& (ship p.lane)
|
%& (ship p.lane)
|
||||||
::
|
::
|
||||||
%|
|
%|
|
||||||
?~ l=((soft ,[=@tas =@if =@ud]) (cue p.lane))
|
%- tape
|
||||||
s+(scot %x p.lane)
|
=/ ip=@if (end [0 32] p.lane)
|
||||||
=, u.l
|
=/ pt=@ud (cut 0 [32 16] p.lane)
|
||||||
(tape "%{(trip tas)}, {(scow %if if)}, {(scow %ud ud)}")
|
"{(scow %if ip)}:{((d-co:co 1) pt)} ({(scow %ux p.lane)})"
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
easy-print=language-server-easy-print,
|
easy-print=language-server-easy-print,
|
||||||
rune-snippet=language-server-rune-snippet,
|
rune-snippet=language-server-rune-snippet,
|
||||||
build=language-server-build,
|
build=language-server-build,
|
||||||
default-agent
|
default-agent, verb
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
+$ lsp-req
|
+$ lsp-req
|
||||||
@ -44,6 +44,7 @@
|
|||||||
==
|
==
|
||||||
--
|
--
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
|
%+ verb |
|
||||||
=| state-zero
|
=| state-zero
|
||||||
=* state -
|
=* state -
|
||||||
=<
|
=<
|
||||||
@ -69,7 +70,7 @@
|
|||||||
|= old-state=vase
|
|= old-state=vase
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
~& > %lsp-upgrade
|
~& > %lsp-upgrade
|
||||||
[~ this(state *state-zero)]
|
[~ this(state !<(state-zero old-state))]
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
^+ on-poke:*agent:gall
|
^+ on-poke:*agent:gall
|
||||||
@ -275,12 +276,14 @@
|
|||||||
++ handle-did-open
|
++ handle-did-open
|
||||||
|= item=text-document-item:lsp-sur
|
|= item=text-document-item:lsp-sur
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
|
=/ =path
|
||||||
|
(uri-to-path:build uri.item)
|
||||||
|
?: ?=(%sys -.path)
|
||||||
|
`state
|
||||||
=/ buf=wall
|
=/ buf=wall
|
||||||
(to-wall (trip text.item))
|
(to-wall (trip text.item))
|
||||||
=. bufs
|
=. bufs
|
||||||
(~(put by bufs) uri.item buf)
|
(~(put by bufs) uri.item buf)
|
||||||
=/ =path
|
|
||||||
(uri-to-path:build uri.item)
|
|
||||||
:_ state
|
:_ state
|
||||||
%+ weld
|
%+ weld
|
||||||
(give-rpc-notification (get-diagnostics uri.item))
|
(give-rpc-notification (get-diagnostics uri.item))
|
||||||
@ -318,12 +321,12 @@
|
|||||||
?~ p.tab-list ~
|
?~ p.tab-list ~
|
||||||
?~ u.p.tab-list ~
|
?~ u.p.tab-list ~
|
||||||
:- ~
|
:- ~
|
||||||
%- crip
|
=- (crip :(weld "```hoon\0a" tape "\0a```"))
|
||||||
;: weld
|
^- =tape
|
||||||
"`"
|
%- zing
|
||||||
~(ram re ~(duck easy-print detail.i.u.p.tab-list))
|
%+ join "\0a"
|
||||||
"`"
|
%+ scag 40
|
||||||
==
|
(~(win re ~(duck easy-print detail.i.u.p.tab-list)) 0 140)
|
||||||
::
|
::
|
||||||
++ sync-buf
|
++ sync-buf
|
||||||
|= [buf=wall changes=(list change:lsp-sur)]
|
|= [buf=wall changes=(list change:lsp-sur)]
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|^ :- %kiln-merge
|
|^ :- %kiln-merge
|
||||||
^- $@(~ [syd=desk her=ship sud=desk cas=case gem=?(germ %auto)])
|
^- $@(~ [syd=desk her=ship sud=desk cas=case gem=?(germ %auto)])
|
||||||
?- arg
|
?- arg
|
||||||
~ ((slog (turn help-text |=(=@t leaf+(trip t)))) ~)
|
~ ((slog (turn `wain`help-text |=(=@t leaf+(trip t)))) ~)
|
||||||
[@ @ ~]
|
[@ @ ~]
|
||||||
=+(arg [sud ?.(=(our her) her (sein:title p.bek now her)) sud (opt-case da+now) gem])
|
=+(arg [sud ?.(=(our her) her (sein:title p.bek now her)) sud (opt-case da+now) gem])
|
||||||
::
|
::
|
||||||
|
@ -61,14 +61,24 @@
|
|||||||
::NOTE we only count graphs for now
|
::NOTE we only count graphs for now
|
||||||
?. &(=(%graph app-name.m) =(our creator.metadatum)) ~
|
?. &(=(%graph app-name.m) =(our creator.metadatum)) ~
|
||||||
`[module.metadatum resource.m]
|
`[module.metadatum resource.m]
|
||||||
|
:: for sanity checks
|
||||||
|
::
|
||||||
|
=/ real=(set resource:re)
|
||||||
|
=/ upd=update:ga
|
||||||
|
%+ scry update:ga
|
||||||
|
[%x %graph-store /keys/graph-update]
|
||||||
|
?> ?=(%keys -.q.upd)
|
||||||
|
resources.q.upd
|
||||||
:: count activity per channel
|
:: count activity per channel
|
||||||
::
|
::
|
||||||
=/ activity=(list [resource:re members=@ud (list [resource:re mod=term week=@ud authors=@ud])])
|
=/ activity=(list [resource:re members=@ud (list [resource:re mod=term week=@ud authors=@ud])])
|
||||||
%+ turn crowds
|
%+ turn crowds
|
||||||
|= [g=resource:re m=@ud]
|
|= [g=resource:re m=@ud]
|
||||||
:+ g m
|
:+ g m
|
||||||
%+ turn (~(got by channels) g)
|
%+ murn (~(got by channels) g)
|
||||||
|= [m=term r=resource:re]
|
|= [m=term r=resource:re]
|
||||||
|
?. (~(has in real) r) ~
|
||||||
|
%- some
|
||||||
:+ r m
|
:+ r m
|
||||||
::NOTE graph-store doesn't use the full resource-style path here!
|
::NOTE graph-store doesn't use the full resource-style path here!
|
||||||
=/ upd=update:ga
|
=/ upd=update:ga
|
||||||
|
15
pkg/arvo/lib/gcp.hoon
Normal file
15
pkg/arvo/lib/gcp.hoon
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/- *gcp
|
||||||
|
|%
|
||||||
|
++ token-to-json
|
||||||
|
|= =token
|
||||||
|
^- json
|
||||||
|
=, enjs:format
|
||||||
|
%+ frond %gcp-token
|
||||||
|
%: pairs
|
||||||
|
[%'accessKey' s+access-key.token]
|
||||||
|
:- %'expiresIn'
|
||||||
|
%- numb
|
||||||
|
(div (mul 1.000 expires-in.token) ~s1)
|
||||||
|
~
|
||||||
|
==
|
||||||
|
--
|
@ -185,6 +185,7 @@
|
|||||||
[%zpmc *] (both p.gen q.gen)
|
[%zpmc *] (both p.gen q.gen)
|
||||||
[%zpts *] loop(gen p.gen)
|
[%zpts *] loop(gen p.gen)
|
||||||
[%zppt *] (both q.gen r.gen)
|
[%zppt *] (both q.gen r.gen)
|
||||||
|
[%zpgl *] (spec-and-hoon p.gen q.gen)
|
||||||
[%zpzp *] ~
|
[%zpzp *] ~
|
||||||
*
|
*
|
||||||
=+ doz=~(open ap gen)
|
=+ doz=~(open ap gen)
|
||||||
@ -245,15 +246,25 @@
|
|||||||
^- (unit [term type])
|
^- (unit [term type])
|
||||||
~
|
~
|
||||||
::
|
::
|
||||||
++ get-id
|
++ get-id-sym
|
||||||
|= [pos=@ud txt=tape]
|
|= [pos=@ud =tape]
|
||||||
^- [forward=(unit @t) backward=(unit @t) id=(unit @t)]
|
%^ get-id pos tape
|
||||||
=/ seek
|
^- $-(nail (like (unit @t)))
|
||||||
|
;~(sfix (punt sym) (star ;~(pose prn (just `@`10))))
|
||||||
|
::
|
||||||
|
++ get-id-cord
|
||||||
|
|= [pos=@ud =tape]
|
||||||
|
%^ get-id pos tape
|
||||||
|
^- $-(nail (like (unit @t)))
|
||||||
;~(sfix (punt (cook crip (star prn))) (star ;~(pose prn (just `@`10))))
|
;~(sfix (punt (cook crip (star prn))) (star ;~(pose prn (just `@`10))))
|
||||||
|
::
|
||||||
|
++ get-id
|
||||||
|
|= [pos=@ud txt=tape seek=$-(nail (like (unit @t)))]
|
||||||
|
^- [forward=(unit @t) backward=(unit @t) id=(unit @t)]
|
||||||
=/ forward=(unit @t)
|
=/ forward=(unit @t)
|
||||||
(scan (slag pos txt) seek)
|
(scan (slag pos txt) seek)
|
||||||
=/ backward=(unit @t)
|
=/ backward=(unit @t)
|
||||||
%- (lift |=(t=@tas (swp 3 t)))
|
%- (lift |=(t=@t (swp 3 t)))
|
||||||
(scan (flop (scag pos txt)) seek)
|
(scan (flop (scag pos txt)) seek)
|
||||||
=/ id=(unit @t)
|
=/ id=(unit @t)
|
||||||
?~ forward
|
?~ forward
|
||||||
@ -272,7 +283,7 @@
|
|||||||
^- [back-pos=@ud fore-pos=@ud txt=tape]
|
^- [back-pos=@ud fore-pos=@ud txt=tape]
|
||||||
:: Find beg-pos by searching backward to where the current term
|
:: Find beg-pos by searching backward to where the current term
|
||||||
:: begins
|
:: begins
|
||||||
=+ (get-id pos txt)
|
=+ (get-id-sym pos txt)
|
||||||
=/ back-pos
|
=/ back-pos
|
||||||
?~ backward
|
?~ backward
|
||||||
pos
|
pos
|
||||||
@ -343,7 +354,7 @@
|
|||||||
[%| p.res]
|
[%| p.res]
|
||||||
:- %&
|
:- %&
|
||||||
~? > debug %parsed-good
|
~? > debug %parsed-good
|
||||||
((cury tab-list-hoon sut) hoon.p.res)
|
((cury tab-list-hoon sut) hoon:`pile:clay`p.res)
|
||||||
::
|
::
|
||||||
:: Generators
|
:: Generators
|
||||||
++ tab-generators
|
++ tab-generators
|
||||||
|
@ -5,75 +5,59 @@
|
|||||||
++ pile-rule
|
++ pile-rule
|
||||||
|= pax=path
|
|= pax=path
|
||||||
%- full
|
%- full
|
||||||
%+ ifix [gay gay]
|
%+ ifix
|
||||||
%+ cook |=(pile +<)
|
:_ gay
|
||||||
;~ pfix
|
|
||||||
:: parse optional /? and ignore
|
:: parse optional /? and ignore
|
||||||
::
|
::
|
||||||
;~ pose
|
;~(plug gay (punt ;~(plug fas wut gap dem gap)))
|
||||||
(cold ~ ;~(plug fas wut gap dem gap))
|
|^
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
|
||||||
;~ plug
|
;~ plug
|
||||||
;~ pose
|
%+ cook (bake zing (list (list taut)))
|
||||||
;~ sfix
|
%+ rune hep
|
||||||
%+ cook |=((list (list taut)) (zing +<))
|
|
||||||
%+ more gap
|
|
||||||
;~ pfix ;~(plug fas hep gap)
|
|
||||||
(most ;~(plug com gaw) taut-rule)
|
(most ;~(plug com gaw) taut-rule)
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
;~ pose
|
%+ cook (bake zing (list (list taut)))
|
||||||
;~ sfix
|
%+ rune lus
|
||||||
%+ cook |=((list (list taut)) (zing +<))
|
|
||||||
%+ more gap
|
|
||||||
;~ pfix ;~(plug fas lus gap)
|
|
||||||
(most ;~(plug com gaw) taut-rule)
|
(most ;~(plug com gaw) taut-rule)
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
;~ pose
|
%+ rune tis
|
||||||
;~ sfix
|
;~(plug sym ;~(pfix gap fas (more fas urs:ab)))
|
||||||
%+ cook |=((list [face=term =path]) +<)
|
|
||||||
%+ more gap
|
|
||||||
;~ pfix ;~(plug fas tis gap)
|
|
||||||
%+ cook |=([term path] +<)
|
|
||||||
;~(plug sym ;~(pfix ;~(plug gap fas) (more fas urs:ab)))
|
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
;~ pose
|
%+ rune cen
|
||||||
;~ sfix
|
;~(plug sym ;~(pfix gap ;~(pfix cen sym)))
|
||||||
%+ cook |=((list [face=term =mark =path]) +<)
|
::
|
||||||
%+ more gap
|
%+ rune buc
|
||||||
;~ pfix ;~(plug fas tar gap)
|
;~ (glue gap)
|
||||||
%+ cook |=([term mark path] +<)
|
|
||||||
;~ plug
|
|
||||||
sym
|
sym
|
||||||
;~(pfix ;~(plug gap cen) sym)
|
;~(pfix cen sym)
|
||||||
;~(pfix ;~(plug gap fas) (more fas urs:ab))
|
;~(pfix cen sym)
|
||||||
==
|
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%+ cook |=(huz=(list hoon) `hoon`tssg+huz)
|
%+ rune tar
|
||||||
|
;~ (glue gap)
|
||||||
|
sym
|
||||||
|
;~(pfix cen sym)
|
||||||
|
;~(pfix fas (more fas urs:ab))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%+ stag %tssg
|
||||||
(most gap tall:(vang & pax))
|
(most gap tall:(vang & pax))
|
||||||
==
|
==
|
||||||
==
|
::
|
||||||
|
++ pant
|
||||||
|
|* fel=^rule
|
||||||
|
;~(pose fel (easy ~))
|
||||||
|
::
|
||||||
|
++ mast
|
||||||
|
|* [bus=^rule fel=^rule]
|
||||||
|
;~(sfix (more bus fel) bus)
|
||||||
|
::
|
||||||
|
++ rune
|
||||||
|
|* [bus=^rule fel=^rule]
|
||||||
|
%- pant
|
||||||
|
%+ mast gap
|
||||||
|
;~(pfix fas bus gap fel)
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ taut-rule
|
++ taut-rule
|
||||||
%+ cook |=(taut +<)
|
%+ cook |=(taut +<)
|
||||||
|
@ -291,7 +291,7 @@
|
|||||||
++ tab
|
++ tab
|
||||||
|= pos=@ud
|
|= pos=@ud
|
||||||
^- (quip card _cli-state)
|
^- (quip card _cli-state)
|
||||||
=+ (get-id:auto pos (tufa buf.cli-state))
|
=+ (get-id-cord:auto pos (tufa buf.cli-state))
|
||||||
=/ needle=term
|
=/ needle=term
|
||||||
(fall id %$)
|
(fall id %$)
|
||||||
:: autocomplete empty command iff user at start of command
|
:: autocomplete empty command iff user at start of command
|
||||||
|
@ -468,9 +468,9 @@
|
|||||||
(strand-fail %build-mark >arg< ~)
|
(strand-fail %build-mark >arg< ~)
|
||||||
?> =(%dais p.r.u.riot)
|
?> =(%dais p.r.u.riot)
|
||||||
(pure:m !<(dais:clay q.r.u.riot))
|
(pure:m !<(dais:clay q.r.u.riot))
|
||||||
:: +build-cast: build a mark conversion gate ($tube)
|
:: +build-tube: build a mark conversion gate ($tube)
|
||||||
::
|
::
|
||||||
++ build-cast
|
++ build-tube
|
||||||
|= [[=ship =desk =case] =mars:clay]
|
|= [[=ship =desk =case] =mars:clay]
|
||||||
=* arg +<
|
=* arg +<
|
||||||
=/ m (strand ,tube:clay)
|
=/ m (strand ,tube:clay)
|
||||||
@ -478,10 +478,37 @@
|
|||||||
;< =riot:clay bind:m
|
;< =riot:clay bind:m
|
||||||
(warp ship desk ~ %sing %c case /[a.mars]/[b.mars])
|
(warp ship desk ~ %sing %c case /[a.mars]/[b.mars])
|
||||||
?~ riot
|
?~ riot
|
||||||
(strand-fail %build-cast >arg< ~)
|
(strand-fail %build-tube >arg< ~)
|
||||||
?> =(%tube p.r.u.riot)
|
?> =(%tube p.r.u.riot)
|
||||||
(pure:m !<(tube:clay q.r.u.riot))
|
(pure:m !<(tube:clay q.r.u.riot))
|
||||||
::
|
::
|
||||||
|
:: +build-nave: build a mark definition to a $nave
|
||||||
|
::
|
||||||
|
++ build-nave
|
||||||
|
|= [[=ship =desk =case] mak=mark]
|
||||||
|
=* arg +<
|
||||||
|
=/ m (strand ,vase)
|
||||||
|
^- form:m
|
||||||
|
;< =riot:clay bind:m
|
||||||
|
(warp ship desk ~ %sing %b case /[mak])
|
||||||
|
?~ riot
|
||||||
|
(strand-fail %build-nave >arg< ~)
|
||||||
|
?> =(%nave p.r.u.riot)
|
||||||
|
(pure:m q.r.u.riot)
|
||||||
|
:: +build-cast: build a mark conversion gate (static)
|
||||||
|
::
|
||||||
|
++ build-cast
|
||||||
|
|= [[=ship =desk =case] =mars:clay]
|
||||||
|
=* arg +<
|
||||||
|
=/ m (strand ,vase)
|
||||||
|
^- form:m
|
||||||
|
;< =riot:clay bind:m
|
||||||
|
(warp ship desk ~ %sing %f case /[a.mars]/[b.mars])
|
||||||
|
?~ riot
|
||||||
|
(strand-fail %build-cast >arg< ~)
|
||||||
|
?> =(%cast p.r.u.riot)
|
||||||
|
(pure:m q.r.u.riot)
|
||||||
|
::
|
||||||
:: Read from Clay
|
:: Read from Clay
|
||||||
::
|
::
|
||||||
++ warp
|
++ warp
|
||||||
|
@ -11,6 +11,6 @@
|
|||||||
--
|
--
|
||||||
++ grab :: convert from
|
++ grab :: convert from
|
||||||
|%
|
|%
|
||||||
++ noun [path @] :: clam from %noun
|
+$ noun [path @] :: clam from %noun
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
=, html
|
=, html
|
||||||
|_ own=manx
|
|_ own=manx
|
||||||
::
|
::
|
||||||
++ grad %mime
|
++ grad %noun
|
||||||
++ grow :: convert to
|
++ grow :: convert to
|
||||||
|%
|
|%
|
||||||
++ hymn ;html:(head body:"+{own}") :: convert to %hymn
|
++ hymn ;html:(head body:"+{own}") :: convert to %hymn
|
||||||
|
13
pkg/arvo/mar/gcp-token.hoon
Normal file
13
pkg/arvo/mar/gcp-token.hoon
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/+ *gcp
|
||||||
|
|_ tok=token
|
||||||
|
++ grad %noun
|
||||||
|
++ grow
|
||||||
|
|%
|
||||||
|
++ noun tok
|
||||||
|
++ json (token-to-json tok)
|
||||||
|
--
|
||||||
|
++ grab
|
||||||
|
|%
|
||||||
|
++ noun token
|
||||||
|
--
|
||||||
|
--
|
@ -6,7 +6,7 @@
|
|||||||
=, format
|
=, format
|
||||||
|_ txt=cord
|
|_ txt=cord
|
||||||
::
|
::
|
||||||
++ grad %mime
|
++ grad %noun
|
||||||
++ grab :: convert from
|
++ grab :: convert from
|
||||||
|%
|
|%
|
||||||
++ noun @t :: clam from %noun
|
++ noun @t :: clam from %noun
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
:::: compute
|
:::: compute
|
||||||
::
|
::
|
||||||
=, html
|
=, html
|
||||||
^|
|
|
||||||
|_ htm=@t
|
|_ htm=@t
|
||||||
++ grow :: convert to
|
++ grow :: convert to
|
||||||
^?
|
^?
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
=, html
|
=, html
|
||||||
|_ own=manx
|
|_ own=manx
|
||||||
::
|
::
|
||||||
++ grad %mime
|
++ grad %noun
|
||||||
++ grow :: convert to
|
++ grow :: convert to
|
||||||
|%
|
|%
|
||||||
++ html (crip (en-xml own)) :: convert to %html
|
++ html (crip (en-xml own)) :: convert to %html
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
++ grad %noun
|
++ grad %noun
|
||||||
++ grab
|
++ grab
|
||||||
|%
|
|%
|
||||||
++ noun not
|
++ noun all:notification
|
||||||
++ json
|
++ json
|
||||||
|= jon=^json
|
|= jon=^json
|
||||||
(notification:dejs:lsp-json jon)
|
(notification:dejs:lsp-json jon)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
--
|
--
|
||||||
++ grab
|
++ grab
|
||||||
|%
|
|%
|
||||||
++ noun req
|
++ noun all:request
|
||||||
++ json
|
++ json
|
||||||
|= jon=^json
|
|= jon=^json
|
||||||
(request:dejs:lsp-json jon)
|
(request:dejs:lsp-json jon)
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
::
|
::
|
||||||
/? 310
|
/? 310
|
||||||
::
|
::
|
||||||
^|
|
|
||||||
|_ own=mime
|
|_ own=mime
|
||||||
++ grow
|
++ grow
|
||||||
^?
|
^?
|
||||||
@ -14,7 +13,7 @@
|
|||||||
++ grab :: convert from
|
++ grab :: convert from
|
||||||
^?
|
^?
|
||||||
|%
|
|%
|
||||||
+$ noun mime :: clam from %noun
|
++ noun mime :: clam from %noun
|
||||||
++ tape
|
++ tape
|
||||||
|=(a=_"" [/application/x-urb-unknown (as-octt:mimes:html a)])
|
|=(a=_"" [/application/x-urb-unknown (as-octt:mimes:html a)])
|
||||||
--
|
--
|
||||||
@ -25,5 +24,9 @@
|
|||||||
++ diff |=(mime +<)
|
++ diff |=(mime +<)
|
||||||
++ pact |=(mime +<)
|
++ pact |=(mime +<)
|
||||||
++ join |=([mime mime] `(unit mime)`~)
|
++ join |=([mime mime] `(unit mime)`~)
|
||||||
|
++ mash
|
||||||
|
|= [[ship desk mime] [ship desk mime]]
|
||||||
|
^- mime
|
||||||
|
~|(%mime-mash !!)
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
@ -14,5 +14,6 @@
|
|||||||
++ diff |=(* +<)
|
++ diff |=(* +<)
|
||||||
++ pact |=(* +<)
|
++ pact |=(* +<)
|
||||||
++ join |=([* *] *(unit *))
|
++ join |=([* *] *(unit *))
|
||||||
|
++ mash |=([[ship desk *] [ship desk *]] `*`~|(%noun-mash !!))
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
++ mime
|
++ mime
|
||||||
|= (pair mite octs)
|
|= (pair mite octs)
|
||||||
=+ o=(pair ,* ,*) :: ,*)
|
=+ o=(pair ,* ,*) :: ,*)
|
||||||
=+ (,[boot-ova=* kernel-ova=(list o) userspace-ova=(list o)] (cue q.q))
|
=+ (,[%pill nam=term boot-ova=(list) kernel-ova=(list o) userspace-ova=(list o)] (cue q.q))
|
||||||
=/ convert
|
=/ convert
|
||||||
|= ova=(list o)
|
|= ova=(list o)
|
||||||
^- (list unix-event)
|
^- (list unix-event)
|
||||||
@ -30,7 +30,7 @@
|
|||||||
:: =/ boot-ova (convert boot-ova)
|
:: =/ boot-ova (convert boot-ova)
|
||||||
=/ kernel-ova (convert kernel-ova)
|
=/ kernel-ova (convert kernel-ova)
|
||||||
=/ userspace-ova (convert userspace-ova)
|
=/ userspace-ova (convert userspace-ova)
|
||||||
[boot-ova kernel-ova userspace-ova]
|
[%pill nam boot-ova kernel-ova userspace-ova]
|
||||||
--
|
--
|
||||||
++ grad %mime
|
++ grad %mime
|
||||||
--
|
--
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|_ dat=@t
|
|_ dat=@
|
||||||
++ grow
|
++ grow
|
||||||
|%
|
|%
|
||||||
++ mime [/image/png (as-octs:mimes:html dat)]
|
++ mime [/image/png (as-octs:mimes:html dat)]
|
||||||
@ -6,7 +6,7 @@
|
|||||||
++ grab
|
++ grab
|
||||||
|%
|
|%
|
||||||
++ mime |=([p=mite q=octs] q.q)
|
++ mime |=([p=mite q=octs] q.q)
|
||||||
++ noun @t
|
++ noun @
|
||||||
--
|
--
|
||||||
++ grad %mime
|
++ grad %mime
|
||||||
--
|
--
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
::
|
::
|
||||||
=, mimes:html
|
=, mimes:html
|
||||||
|_ [hed=marl tal=marl]
|
|_ [hed=marl tal=marl]
|
||||||
++ grad %mime
|
++ grad %noun
|
||||||
::
|
::
|
||||||
++ grow :: convert to
|
++ grow :: convert to
|
||||||
|%
|
|%
|
||||||
@ -55,6 +55,7 @@
|
|||||||
++ html (crip (en-xml hymn)) :: convert to %html
|
++ html (crip (en-xml hymn)) :: convert to %html
|
||||||
++ mime [/text/html (as-octs html)] :: convert to %mime
|
++ mime [/text/html (as-octs html)] :: convert to %mime
|
||||||
--
|
--
|
||||||
|
++ noun [hed tal]
|
||||||
--
|
--
|
||||||
++ grab |% :: convert from
|
++ grab |% :: convert from
|
||||||
++ noun ,[marl marl] :: clam from %noun
|
++ noun ,[marl marl] :: clam from %noun
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
=, html
|
=, html
|
||||||
|_ own=manx
|
|_ own=manx
|
||||||
::
|
::
|
||||||
++ grad %mime
|
++ grad %noun
|
||||||
++ grow :: convert to
|
++ grow :: convert to
|
||||||
|%
|
|%
|
||||||
++ hymn ;html:(head body:"+{own}") :: convert to %hymn
|
++ hymn ;html:(head body:"+{own}") :: convert to %hymn
|
||||||
|
6
pkg/arvo/sur/gcp.hoon
Normal file
6
pkg/arvo/sur/gcp.hoon
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|%
|
||||||
|
+$ token
|
||||||
|
$: access-key=@t
|
||||||
|
expires-in=@dr
|
||||||
|
==
|
||||||
|
--
|
@ -796,7 +796,7 @@
|
|||||||
$: face=(unit term)
|
$: face=(unit term)
|
||||||
file-path=term
|
file-path=term
|
||||||
==
|
==
|
||||||
+$ care ?(%a %b %c %d %p %r %s %t %u %v %w %x %y %z) :: clay submode
|
+$ care ?(%a %b %c %d %e %f %p %r %s %t %u %v %w %x %y %z) :: clay submode
|
||||||
+$ case :: ship desk case spur
|
+$ case :: ship desk case spur
|
||||||
$% [%da p=@da] :: date
|
$% [%da p=@da] :: date
|
||||||
[%tas p=@tas] :: label
|
[%tas p=@tas] :: label
|
||||||
@ -928,12 +928,16 @@
|
|||||||
:: /- sur-file :: surface imports from /sur
|
:: /- sur-file :: surface imports from /sur
|
||||||
:: /+ lib-file :: library imports from /lib
|
:: /+ lib-file :: library imports from /lib
|
||||||
:: /= face /path :: imports built hoon file at path
|
:: /= face /path :: imports built hoon file at path
|
||||||
|
:: /% face %mark :: imports mark definition from /mar
|
||||||
|
:: /$ face %from %to :: imports mark converter from /mar
|
||||||
:: /* face %mark /path :: unbuilt file imports, as mark
|
:: /* face %mark /path :: unbuilt file imports, as mark
|
||||||
::
|
::
|
||||||
+$ pile
|
+$ pile
|
||||||
$: sur=(list taut)
|
$: sur=(list taut)
|
||||||
lib=(list taut)
|
lib=(list taut)
|
||||||
raw=(list [face=term =path])
|
raw=(list [face=term =path])
|
||||||
|
maz=(list [face=term =mark])
|
||||||
|
caz=(list [face=term =mars])
|
||||||
bar=(list [face=term =mark =path])
|
bar=(list [face=term =mark =path])
|
||||||
=hoon
|
=hoon
|
||||||
==
|
==
|
||||||
@ -942,9 +946,25 @@
|
|||||||
+$ taut [face=(unit term) pax=term]
|
+$ taut [face=(unit term) pax=term]
|
||||||
:: $mars: mark conversion request
|
:: $mars: mark conversion request
|
||||||
:: $tube: mark conversion gate
|
:: $tube: mark conversion gate
|
||||||
|
:: $nave: typed mark core
|
||||||
::
|
::
|
||||||
+$ mars [a=mark b=mark]
|
+$ mars [a=mark b=mark]
|
||||||
+$ tube $-(vase vase)
|
+$ tube $-(vase vase)
|
||||||
|
++ nave
|
||||||
|
|$ [typ dif]
|
||||||
|
$_
|
||||||
|
^?
|
||||||
|
|%
|
||||||
|
++ bunt *typ
|
||||||
|
++ diff |~([old=typ new=typ] *dif)
|
||||||
|
++ form *mark
|
||||||
|
++ join |~([a=dif b=dif] *(unit (unit dif)))
|
||||||
|
++ mash
|
||||||
|
|~ [a=[ship desk dif] b=[ship desk dif]]
|
||||||
|
*(unit dif)
|
||||||
|
++ pact |~([typ dif] *typ)
|
||||||
|
++ vale |~(noun *typ)
|
||||||
|
--
|
||||||
:: $dais: processed mark core
|
:: $dais: processed mark core
|
||||||
::
|
::
|
||||||
+$ dais
|
+$ dais
|
||||||
@ -959,7 +979,6 @@
|
|||||||
*(unit vase)
|
*(unit vase)
|
||||||
++ pact |~(diff=vase sam)
|
++ pact |~(diff=vase sam)
|
||||||
++ vale |~(noun sam)
|
++ vale |~(noun sam)
|
||||||
++ volt |~(noun sam)
|
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ get-fit
|
++ get-fit
|
||||||
|
@ -829,7 +829,7 @@
|
|||||||
:: lifecycle arms; mostly pass-throughs to the contained adult ames
|
:: lifecycle arms; mostly pass-throughs to the contained adult ames
|
||||||
::
|
::
|
||||||
++ scry scry:adult-core
|
++ scry scry:adult-core
|
||||||
++ stay [%4 %larva queued-events ames-state.adult-gate]
|
++ stay [%5 %larva queued-events ames-state.adult-gate]
|
||||||
++ load
|
++ load
|
||||||
|= $= old
|
|= $= old
|
||||||
$% $: %4
|
$% $: %4
|
||||||
@ -839,6 +839,13 @@
|
|||||||
==
|
==
|
||||||
[%adult state=_ames-state.adult-gate]
|
[%adult state=_ames-state.adult-gate]
|
||||||
== ==
|
== ==
|
||||||
|
$: %5
|
||||||
|
$% $: %larva
|
||||||
|
events=(qeu queued-event)
|
||||||
|
state=_ames-state.adult-gate
|
||||||
|
==
|
||||||
|
[%adult state=_ames-state.adult-gate]
|
||||||
|
== ==
|
||||||
==
|
==
|
||||||
?- old
|
?- old
|
||||||
[%4 %adult *] (load:adult-core %4 state.old)
|
[%4 %adult *] (load:adult-core %4 state.old)
|
||||||
@ -848,6 +855,14 @@
|
|||||||
=. queued-events events.old
|
=. queued-events events.old
|
||||||
=. adult-gate (load:adult-core %4 state.old)
|
=. adult-gate (load:adult-core %4 state.old)
|
||||||
larval-gate
|
larval-gate
|
||||||
|
::
|
||||||
|
[%5 %adult *] (load:adult-core %5 state.old)
|
||||||
|
::
|
||||||
|
[%5 %larva *]
|
||||||
|
~> %slog.1^leaf/"ames: larva: load"
|
||||||
|
=. queued-events events.old
|
||||||
|
=. adult-gate (load:adult-core %5 state.old)
|
||||||
|
larval-gate
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
:: adult ames, after metamorphosis from larva
|
:: adult ames, after metamorphosis from larva
|
||||||
@ -919,13 +934,38 @@
|
|||||||
[moves ames-gate]
|
[moves ames-gate]
|
||||||
:: +stay: extract state before reload
|
:: +stay: extract state before reload
|
||||||
::
|
::
|
||||||
++ stay [%4 %adult ames-state]
|
++ stay [%5 %adult ames-state]
|
||||||
:: +load: load in old state after reload
|
:: +load: load in old state after reload
|
||||||
::
|
::
|
||||||
++ load
|
++ load
|
||||||
|= old-state=[%4 ^ames-state]
|
|= $= old-state
|
||||||
|
$% [%4 ^ames-state]
|
||||||
|
[%5 ^ames-state]
|
||||||
|
==
|
||||||
|
|^
|
||||||
^+ ames-gate
|
^+ ames-gate
|
||||||
|
=? old-state ?=(%4 -.old-state) %5^(state-4-to-5 +.old-state)
|
||||||
|
::
|
||||||
|
?> ?=(%5 -.old-state)
|
||||||
ames-gate(ames-state +.old-state)
|
ames-gate(ames-state +.old-state)
|
||||||
|
::
|
||||||
|
++ state-4-to-5
|
||||||
|
|= =^ames-state
|
||||||
|
^- ^^ames-state
|
||||||
|
=. peers.ames-state
|
||||||
|
%- ~(run by peers.ames-state)
|
||||||
|
|= =ship-state
|
||||||
|
?. ?=(%known -.ship-state)
|
||||||
|
ship-state
|
||||||
|
=. snd.ship-state
|
||||||
|
%- ~(run by snd.ship-state)
|
||||||
|
|= =message-pump-state
|
||||||
|
=. num-live.metrics.packet-pump-state.message-pump-state
|
||||||
|
~(wyt in live.packet-pump-state.message-pump-state)
|
||||||
|
message-pump-state
|
||||||
|
ship-state
|
||||||
|
ames-state
|
||||||
|
--
|
||||||
:: +scry: dereference namespace
|
:: +scry: dereference namespace
|
||||||
::
|
::
|
||||||
++ scry
|
++ scry
|
||||||
@ -1904,6 +1944,11 @@
|
|||||||
=/ =bone bone.shut-packet
|
=/ =bone bone.shut-packet
|
||||||
::
|
::
|
||||||
?: ?=(%& -.meat.shut-packet)
|
?: ?=(%& -.meat.shut-packet)
|
||||||
|
=+ ?~ dud ~
|
||||||
|
%. ~
|
||||||
|
%+ slog
|
||||||
|
leaf+"ames: {<her.channel>} fragment crashed {<mote.u.dud>}"
|
||||||
|
?.(msg.veb ~ tang.u.dud)
|
||||||
(run-message-sink bone %hear lane shut-packet ?=(~ dud))
|
(run-message-sink bone %hear lane shut-packet ?=(~ dud))
|
||||||
:: Just try again on error, printing trace
|
:: Just try again on error, printing trace
|
||||||
::
|
::
|
||||||
@ -1912,7 +1957,10 @@
|
|||||||
::
|
::
|
||||||
=+ ?~ dud ~
|
=+ ?~ dud ~
|
||||||
%. ~
|
%. ~
|
||||||
(slog leaf+"ames: crashed on message ack" >mote.u.dud< tang.u.dud)
|
%+ slog leaf+"ames: {<her.channel>} ack crashed {<mote.u.dud>}"
|
||||||
|
?. msg.veb ~
|
||||||
|
:- >[bone=bone message-num=message-num meat=meat]:shut-packet<
|
||||||
|
tang.u.dud
|
||||||
(run-message-pump bone %hear [message-num +.meat]:shut-packet)
|
(run-message-pump bone %hear [message-num +.meat]:shut-packet)
|
||||||
:: +on-memo: handle request to send message
|
:: +on-memo: handle request to send message
|
||||||
::
|
::
|
||||||
@ -2198,12 +2246,15 @@
|
|||||||
?. ?=([%hear * * ok=%.n] task)
|
?. ?=([%hear * * ok=%.n] task)
|
||||||
:: fresh boon; give message to client vane
|
:: fresh boon; give message to client vane
|
||||||
::
|
::
|
||||||
%- (trace msg.veb |.("boon {<her.channel^bone=bone -.task>}"))
|
%- %+ trace msg.veb
|
||||||
|
=/ dat [her.channel bone=bone message-num=message-num -.task]
|
||||||
|
|.("sink boon {<dat>}")
|
||||||
peer-core
|
peer-core
|
||||||
:: we previously crashed on this message; notify client vane
|
:: we previously crashed on this message; notify client vane
|
||||||
::
|
::
|
||||||
%- %+ trace msg.veb
|
%- %+ trace msg.veb
|
||||||
|.("crashed on boon {<her.channel^bone=bone -.task>}")
|
=/ dat [her.channel bone=bone message-num=message-num -.task]
|
||||||
|
|.("crashed on sink boon {<dat>}")
|
||||||
boon-to-lost
|
boon-to-lost
|
||||||
:: +boon-to-lost: convert all boons to losts
|
:: +boon-to-lost: convert all boons to losts
|
||||||
::
|
::
|
||||||
@ -2221,7 +2272,9 @@
|
|||||||
++ on-sink-nack-trace
|
++ on-sink-nack-trace
|
||||||
|= [=message-num message=*]
|
|= [=message-num message=*]
|
||||||
^+ peer-core
|
^+ peer-core
|
||||||
%- (trace msg.veb |.("nack trace {<her.channel^bone=bone>}"))
|
%- %+ trace msg.veb
|
||||||
|
=/ dat [her.channel bone=bone message-num=message-num]
|
||||||
|
|.("sink naxplanation {<dat>}")
|
||||||
::
|
::
|
||||||
=+ ;; =naxplanation message
|
=+ ;; =naxplanation message
|
||||||
:: ack nack-trace message (only applied if we don't later crash)
|
:: ack nack-trace message (only applied if we don't later crash)
|
||||||
@ -2238,7 +2291,9 @@
|
|||||||
++ on-sink-plea
|
++ on-sink-plea
|
||||||
|= [=message-num message=*]
|
|= [=message-num message=*]
|
||||||
^+ peer-core
|
^+ peer-core
|
||||||
%- (trace msg.veb |.("plea {<her.channel^bone=bone>}"))
|
%- %+ trace msg.veb
|
||||||
|
=/ dat [her.channel bone=bone message-num=message-num]
|
||||||
|
|.("sink plea {<dat>}")
|
||||||
:: is this the first time we're trying to process this message?
|
:: is this the first time we're trying to process this message?
|
||||||
::
|
::
|
||||||
?. ?=([%hear * * ok=%.n] task)
|
?. ?=([%hear * * ok=%.n] task)
|
||||||
|
@ -118,9 +118,11 @@
|
|||||||
:: Ford cache
|
:: Ford cache
|
||||||
::
|
::
|
||||||
+$ ford-cache
|
+$ ford-cache
|
||||||
$: vases=(map path [res=vase dez=(set path)])
|
$: files=(map path [res=vase dez=(set path)])
|
||||||
|
naves=(map mark [res=vase dez=(set path)])
|
||||||
marks=(map mark [res=dais dez=(set path)])
|
marks=(map mark [res=dais dez=(set path)])
|
||||||
casts=(map mars [res=tube dez=(set path)])
|
casts=(map mars [res=vase dez=(set path)])
|
||||||
|
tubes=(map mars [res=tube dez=(set path)])
|
||||||
==
|
==
|
||||||
:: $reef-cache: built system files
|
:: $reef-cache: built system files
|
||||||
::
|
::
|
||||||
@ -462,7 +464,9 @@
|
|||||||
+$ build
|
+$ build
|
||||||
$% [%file =path]
|
$% [%file =path]
|
||||||
[%mark =mark]
|
[%mark =mark]
|
||||||
|
[%dais =mark]
|
||||||
[%cast =mars]
|
[%cast =mars]
|
||||||
|
[%tube =mars]
|
||||||
[%vale =path]
|
[%vale =path]
|
||||||
==
|
==
|
||||||
+$ state
|
+$ state
|
||||||
@ -494,8 +498,9 @@
|
|||||||
=? stack.nub ?=(^ stack.nub)
|
=? stack.nub ?=(^ stack.nub)
|
||||||
stack.nub(i (~(uni in i.stack.nub) top))
|
stack.nub(i (~(uni in i.stack.nub) top))
|
||||||
[top stack.nub]
|
[top stack.nub]
|
||||||
|
:: +read-file: retrieve marked, validated file contents at path
|
||||||
::
|
::
|
||||||
++ get-value
|
++ read-file
|
||||||
|= =path
|
|= =path
|
||||||
^- [cage state]
|
^- [cage state]
|
||||||
~| %error-validating^path
|
~| %error-validating^path
|
||||||
@ -519,13 +524,13 @@
|
|||||||
?< (~(has in deletes) path)
|
?< (~(has in deletes) path)
|
||||||
~| %file-not-found^path
|
~| %file-not-found^path
|
||||||
:_(nub (need (~(get an ankh) path)))
|
:_(nub (need (~(get an ankh) path)))
|
||||||
:: +get-mark: build a mark definition
|
:: +build-nave: build a statically typed mark core
|
||||||
::
|
::
|
||||||
++ get-mark
|
++ build-nave
|
||||||
|= mak=mark
|
|= mak=mark
|
||||||
^- [dais state]
|
^- [vase state]
|
||||||
~| %error-building-mark^mak
|
~| %error-building-mark^mak
|
||||||
?^ got=(~(get by marks.cache.nub) mak)
|
?^ got=(~(get by naves.cache.nub) mak)
|
||||||
=? stack.nub ?=(^ stack.nub)
|
=? stack.nub ?=(^ stack.nub)
|
||||||
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
||||||
[res.u.got nub]
|
[res.u.got nub]
|
||||||
@ -533,99 +538,128 @@
|
|||||||
~|(cycle+mark+mak^stack.nub !!)
|
~|(cycle+mark+mak^stack.nub !!)
|
||||||
=. cycle.nub (~(put in cycle.nub) mark+mak)
|
=. cycle.nub (~(put in cycle.nub) mark+mak)
|
||||||
=. stack.nub [~ stack.nub]
|
=. stack.nub [~ stack.nub]
|
||||||
|
=; res=[=vase nub=state]
|
||||||
|
=. nub nub.res
|
||||||
|
=^ top stack.nub pop-stack
|
||||||
|
=. naves.cache.nub (~(put by naves.cache.nub) mak [vase.res top])
|
||||||
|
[vase.res nub]
|
||||||
|
=^ cor=vase nub (build-fit %mar mak)
|
||||||
|
=/ gad=vase (slap cor limb/%grad)
|
||||||
|
?@ q.gad
|
||||||
|
=+ !<(mok=mark gad)
|
||||||
|
=^ deg=vase nub $(mak mok)
|
||||||
|
=^ tub=vase nub (build-cast mak mok)
|
||||||
|
=^ but=vase nub (build-cast mok mak)
|
||||||
|
:_ nub
|
||||||
|
^- vase :: vase of nave
|
||||||
|
%+ slap
|
||||||
|
(with-faces deg+deg tub+tub but+but cor+cor nave+!>(nave) ~)
|
||||||
|
!, *hoon
|
||||||
|
=/ typ _+<.cor
|
||||||
|
=/ dif diff:deg
|
||||||
|
^- (nave typ dif)
|
||||||
|
|%
|
||||||
|
++ bunt +<.cor
|
||||||
|
++ diff
|
||||||
|
|= [old=typ new=typ]
|
||||||
|
^- dif
|
||||||
|
(diff:deg (tub old) (tub new))
|
||||||
|
++ form form:deg
|
||||||
|
++ join join:deg
|
||||||
|
++ mash mash:deg
|
||||||
|
++ pact
|
||||||
|
|= [v=typ d=dif]
|
||||||
|
^- typ
|
||||||
|
(but (pact:deg (tub v) d))
|
||||||
|
++ vale noun:grab:cor
|
||||||
|
--
|
||||||
|
:_ nub
|
||||||
|
^- vase :: vase of nave
|
||||||
|
%+ slap (slop (with-face cor+cor) bud)
|
||||||
|
!, *hoon
|
||||||
|
=/ typ _+<.cor
|
||||||
|
=/ dif _*diff:grad:cor
|
||||||
|
^- (nave:clay typ dif)
|
||||||
|
|%
|
||||||
|
++ bunt +<.cor
|
||||||
|
++ diff |=([old=typ new=typ] (diff:~(grad cor old) new))
|
||||||
|
++ form form:grad:cor
|
||||||
|
++ join
|
||||||
|
|= [a=dif b=dif]
|
||||||
|
^- (unit (unit dif))
|
||||||
|
?: =(a b)
|
||||||
|
~
|
||||||
|
`(join:grad:cor a b)
|
||||||
|
++ mash
|
||||||
|
|= [a=[=ship =desk =dif] b=[=ship =desk =dif]]
|
||||||
|
^- (unit dif)
|
||||||
|
?: =(dif.a dif.b)
|
||||||
|
~
|
||||||
|
`(mash:grad:cor a b)
|
||||||
|
++ pact |=([v=typ d=dif] (pact:~(grad cor v) d))
|
||||||
|
++ vale noun:grab:cor
|
||||||
|
--
|
||||||
|
:: +build-dais: build a dynamically typed mark definition
|
||||||
|
::
|
||||||
|
++ build-dais
|
||||||
|
|= mak=mark
|
||||||
|
^- [dais state]
|
||||||
|
~| %error-building-dais^mak
|
||||||
|
?^ got=(~(get by marks.cache.nub) mak)
|
||||||
|
=? stack.nub ?=(^ stack.nub)
|
||||||
|
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
||||||
|
[res.u.got nub]
|
||||||
|
?: (~(has in cycle.nub) dais+mak)
|
||||||
|
~|(cycle+dais+mak^stack.nub !!)
|
||||||
|
=. cycle.nub (~(put in cycle.nub) dais+mak)
|
||||||
|
=. stack.nub [~ stack.nub]
|
||||||
=; res=[=dais nub=state]
|
=; res=[=dais nub=state]
|
||||||
=. nub nub.res
|
=. nub nub.res
|
||||||
=^ top stack.nub pop-stack
|
=^ top stack.nub pop-stack
|
||||||
=. marks.cache.nub (~(put by marks.cache.nub) mak [dais.res top])
|
=. marks.cache.nub (~(put by marks.cache.nub) mak [dais.res top])
|
||||||
[dais.res nub]
|
[dais.res nub]
|
||||||
=^ cor=vase nub (build-fit %mar mak)
|
=^ nav=vase nub (build-nave mak)
|
||||||
=/ gad=vase (slap cor %limb %grad)
|
|
||||||
?@ q.gad
|
|
||||||
=+ !<(mok=mark gad)
|
|
||||||
=^ deg=dais nub $(mak mok)
|
|
||||||
=^ tub=tube nub (get-cast mak mok)
|
|
||||||
=^ but=tube nub (get-cast mok mak)
|
|
||||||
:_ nub
|
:_ nub
|
||||||
^- dais
|
^- dais
|
||||||
|_ sam=vase
|
|_ sam=vase
|
||||||
++ bunt (slap cor $+6)
|
++ bunt (slap nav limb/%bunt)
|
||||||
++ diff
|
++ diff
|
||||||
|= new=vase
|
|= new=vase
|
||||||
^- vase
|
(slam (slap nav limb/%diff) (slop sam new))
|
||||||
(~(diff deg (tub sam)) (tub new))
|
++ form !<(mark (slap nav limb/%form))
|
||||||
++ form form:deg
|
|
||||||
++ join join:deg
|
|
||||||
++ mash mash:deg
|
|
||||||
++ pact
|
|
||||||
|= diff=vase
|
|
||||||
^+ sam
|
|
||||||
(but (~(pact deg (tub sam)) diff))
|
|
||||||
++ vale
|
|
||||||
|= =noun
|
|
||||||
^+ sam
|
|
||||||
(slam (slap cor !,(*hoon noun:grab)) !>(noun))
|
|
||||||
++ volt
|
|
||||||
|= =noun
|
|
||||||
^+ sam
|
|
||||||
[p:bunt noun]
|
|
||||||
--
|
|
||||||
:_ nub
|
|
||||||
=+ !<(fom=mark (slap gad %limb %form))
|
|
||||||
^- dais
|
|
||||||
|_ sam=vase
|
|
||||||
++ bunt (slap cor $+6)
|
|
||||||
++ diff
|
|
||||||
|= new=vase
|
|
||||||
^- vase
|
|
||||||
%+ slap
|
|
||||||
(with-faces cor+cor sam+sam new+new ~)
|
|
||||||
!, *hoon
|
|
||||||
(diff:~(grad cor sam) new)
|
|
||||||
++ form fom
|
|
||||||
++ join
|
++ join
|
||||||
|= [a=vase b=vase]
|
|= [a=vase b=vase]
|
||||||
^- (unit (unit vase))
|
^- (unit (unit vase))
|
||||||
?: =(q.a q.b)
|
=/ res=vase (slam (slap nav limb/%join) (slop a b))
|
||||||
~
|
?~ q.res ~
|
||||||
=; res `?~(q.res ~ `(slap res !,(*hoon ?~(. !! u))))
|
?~ +.q.res [~ ~]
|
||||||
(slam (slap cor !,(*hoon join:grad)) (slop a b))
|
``(slap res !,(*hoon ?>(?=([~ ~ *] .) u.u)))
|
||||||
++ mash
|
++ mash
|
||||||
|= [a=[=ship =desk diff=vase] b=[=ship =desk diff=vase]]
|
|= [a=[=ship =desk diff=vase] b=[=ship =desk diff=vase]]
|
||||||
^- (unit vase)
|
^- (unit vase)
|
||||||
?: =(q.diff.a q.diff.b)
|
=/ res=vase
|
||||||
~
|
%+ slam (slap nav limb/%mash)
|
||||||
:- ~
|
|
||||||
%+ slam (slap cor !,(*hoon mash:grad))
|
|
||||||
%+ slop
|
%+ slop
|
||||||
:(slop !>(ship.a) !>(desk.a) diff.a)
|
:(slop !>(ship.a) !>(desk.a) diff.a)
|
||||||
:(slop !>(ship.b) !>(desk.b) diff.b)
|
:(slop !>(ship.b) !>(desk.b) diff.b)
|
||||||
|
?~ q.res
|
||||||
|
~
|
||||||
|
`(slap res !,(*hoon ?>((^ .) u)))
|
||||||
++ pact
|
++ pact
|
||||||
|= diff=vase
|
|= diff=vase
|
||||||
^+ sam
|
(slam (slap nav limb/%pact) (slop sam diff))
|
||||||
%+ slap
|
|
||||||
(with-faces cor+cor sam+sam diff+diff ~)
|
|
||||||
!, *hoon
|
|
||||||
(pact:~(grad cor sam) diff)
|
|
||||||
++ vale
|
++ vale
|
||||||
|= =noun
|
|= =noun
|
||||||
^+ sam
|
(slam (slap nav limb/%vale) noun/noun)
|
||||||
(slam (slap cor !,(*hoon noun:grab)) !>(noun))
|
|
||||||
++ volt
|
|
||||||
|= =noun
|
|
||||||
^+ sam
|
|
||||||
[p:bunt noun]
|
|
||||||
--
|
--
|
||||||
:: +get-cast: produce a $tube mark conversion gate from .a to .b
|
:: +build-cast: produce gate to convert mark .a to, statically typed
|
||||||
::
|
::
|
||||||
++ get-cast
|
++ build-cast
|
||||||
|= [a=mark b=mark]
|
|= [a=mark b=mark]
|
||||||
^- [tube state]
|
^- [vase state]
|
||||||
~| error-building-cast+[a b]
|
~| error-building-cast+[a b]
|
||||||
?: =([%mime %hoon] [a b])
|
?: =([%mime %hoon] [a b])
|
||||||
:_ nub
|
:_(nub !>(|=(m=mime q.q.m)))
|
||||||
|= sam=vase
|
|
||||||
=+ !<(=mime sam)
|
|
||||||
!>(q.q.mime)
|
|
||||||
?^ got=(~(get by casts.cache.nub) [a b])
|
?^ got=(~(get by casts.cache.nub) [a b])
|
||||||
=? stack.nub ?=(^ stack.nub)
|
=? stack.nub ?=(^ stack.nub)
|
||||||
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
||||||
@ -633,11 +667,11 @@
|
|||||||
?: (~(has in cycle.nub) cast+[a b])
|
?: (~(has in cycle.nub) cast+[a b])
|
||||||
~|(cycle+cast+[a b]^stack.nub !!)
|
~|(cycle+cast+[a b]^stack.nub !!)
|
||||||
=. stack.nub [~ stack.nub]
|
=. stack.nub [~ stack.nub]
|
||||||
=; res=[=tube nub=state]
|
=; res=[=vase nub=state]
|
||||||
=. nub nub.res
|
=. nub nub.res
|
||||||
=^ top stack.nub pop-stack
|
=^ top stack.nub pop-stack
|
||||||
=. casts.cache.nub (~(put by casts.cache.nub) [a b] [tube.res top])
|
=. casts.cache.nub (~(put by casts.cache.nub) [a b] [vase.res top])
|
||||||
[tube.res nub]
|
[vase.res nub]
|
||||||
:: try +grow; is there a +grow core with a .b arm?
|
:: try +grow; is there a +grow core with a .b arm?
|
||||||
::
|
::
|
||||||
=^ old=vase nub (build-fit %mar a)
|
=^ old=vase nub (build-fit %mar a)
|
||||||
@ -649,47 +683,57 @@
|
|||||||
:: +grow core has .b arm; use that
|
:: +grow core has .b arm; use that
|
||||||
::
|
::
|
||||||
:_ nub
|
:_ nub
|
||||||
^- tube
|
%+ slap (with-faces cor+old ~)
|
||||||
|= sam=vase
|
^- hoon
|
||||||
^- vase
|
:+ %brcl !,(*hoon v=+<.cor)
|
||||||
%+ slap
|
:+ %tsgl limb/b
|
||||||
(with-faces old+old sam+sam ~)
|
!,(*hoon ~(grow cor v))
|
||||||
:+ %sgzp !,(*hoon old=old)
|
|
||||||
:+ %sgzp !,(*hoon sam=sam)
|
|
||||||
:+ %tsgl [%limb b]
|
|
||||||
!, *hoon
|
|
||||||
~(grow old sam)
|
|
||||||
:: try direct +grab
|
:: try direct +grab
|
||||||
::
|
::
|
||||||
=^ new=vase nub (build-fit %mar b)
|
=^ new=vase nub (build-fit %mar b)
|
||||||
=/ rab
|
=/ rab (mule |.((slap new tsgl/[limb/a limb/%grab])))
|
||||||
%- mule |.
|
|
||||||
%+ slap new
|
|
||||||
:+ %tsgl [%limb a]
|
|
||||||
[%limb %grab]
|
|
||||||
?: &(?=(%& -.rab) ?=(^ q.p.rab))
|
?: &(?=(%& -.rab) ?=(^ q.p.rab))
|
||||||
:_(nub |=(sam=vase ~|([%grab a b] (slam p.rab sam))))
|
:_(nub p.rab)
|
||||||
:: try +jump
|
:: try +jump
|
||||||
::
|
::
|
||||||
=/ jum
|
=/ jum (mule |.((slap old tsgl/[limb/b limb/%jump])))
|
||||||
%- mule |.
|
|
||||||
%+ slap old
|
|
||||||
:+ %tsgl [%limb b]
|
|
||||||
[%limb %jump]
|
|
||||||
?: ?=(%& -.jum)
|
?: ?=(%& -.jum)
|
||||||
(compose-casts a !<(mark p.jum) b)
|
(compose-casts a !<(mark p.jum) b)
|
||||||
:: try indirect +grab
|
|
||||||
::
|
|
||||||
?: ?=(%& -.rab)
|
?: ?=(%& -.rab)
|
||||||
(compose-casts a !<(mark p.rab) b)
|
(compose-casts a !<(mark p.rab) b)
|
||||||
|
?: ?=(%noun b)
|
||||||
|
:_(nub !>(|=(* +<)))
|
||||||
~|(no-cast-from+[a b] !!)
|
~|(no-cast-from+[a b] !!)
|
||||||
::
|
::
|
||||||
++ compose-casts
|
++ compose-casts
|
||||||
|= [x=mark y=mark z=mark]
|
|= [x=mark y=mark z=mark]
|
||||||
|
^- [vase state]
|
||||||
|
=^ uno=vase nub (build-cast x y)
|
||||||
|
=^ dos=vase nub (build-cast y z)
|
||||||
|
:_ nub
|
||||||
|
%+ slap
|
||||||
|
(with-faces uno+uno dos+dos cork+!>(cork) ~)
|
||||||
|
!,(*hoon (cork uno dos))
|
||||||
|
:: +build-tube: produce a $tube mark conversion gate from .a to .b
|
||||||
|
::
|
||||||
|
++ build-tube
|
||||||
|
|= [a=mark b=mark]
|
||||||
^- [tube state]
|
^- [tube state]
|
||||||
=^ uno=tube nub (get-cast x y)
|
~| error-building-tube+[a b]
|
||||||
=^ dos=tube nub (get-cast y z)
|
?^ got=(~(get by tubes.cache.nub) [a b])
|
||||||
:_(nub |=(sam=vase (dos (uno sam))))
|
=? stack.nub ?=(^ stack.nub)
|
||||||
|
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
||||||
|
[res.u.got nub]
|
||||||
|
?: (~(has in cycle.nub) tube+[a b])
|
||||||
|
~|(cycle+tube+[a b]^stack.nub !!)
|
||||||
|
=. stack.nub [~ stack.nub]
|
||||||
|
=; res=[=tube nub=state]
|
||||||
|
=. nub nub.res
|
||||||
|
=^ top stack.nub pop-stack
|
||||||
|
=. tubes.cache.nub (~(put by tubes.cache.nub) [a b] [tube.res top])
|
||||||
|
[tube.res nub]
|
||||||
|
=^ gat=vase nub (build-cast a b)
|
||||||
|
:_(nub |=(v=vase (slam gat v)))
|
||||||
::
|
::
|
||||||
++ lobe-to-page
|
++ lobe-to-page
|
||||||
|= =lobe
|
|= =lobe
|
||||||
@ -713,7 +757,7 @@
|
|||||||
?: =(mak p.page)
|
?: =(mak p.page)
|
||||||
(page-to-cage page)
|
(page-to-cage page)
|
||||||
=^ [mark vax=vase] nub (page-to-cage page)
|
=^ [mark vax=vase] nub (page-to-cage page)
|
||||||
=^ =tube nub (get-cast p.page mak)
|
=^ =tube nub (build-tube p.page mak)
|
||||||
:_(nub [mak (tube vax)])
|
:_(nub [mak (tube vax)])
|
||||||
::
|
::
|
||||||
++ page-to-cage
|
++ page-to-cage
|
||||||
@ -723,7 +767,7 @@
|
|||||||
:_(nub [%hoon -:!>(*@t) q.page])
|
:_(nub [%hoon -:!>(*@t) q.page])
|
||||||
?: =(%mime p.page)
|
?: =(%mime p.page)
|
||||||
:_(nub [%mime !>(;;(mime q.page))])
|
:_(nub [%mime !>(;;(mime q.page))])
|
||||||
=^ =dais nub (get-mark p.page)
|
=^ =dais nub (build-dais p.page)
|
||||||
:_(nub [p.page (vale:dais q.page)])
|
:_(nub [p.page (vale:dais q.page)])
|
||||||
::
|
::
|
||||||
++ cast-path
|
++ cast-path
|
||||||
@ -731,10 +775,10 @@
|
|||||||
^- [cage state]
|
^- [cage state]
|
||||||
=/ mok (head (flop path))
|
=/ mok (head (flop path))
|
||||||
~| error-casting-path+[path mok mak]
|
~| error-casting-path+[path mok mak]
|
||||||
=^ cag=cage nub (get-value path)
|
=^ cag=cage nub (read-file path)
|
||||||
?: =(mok mak)
|
?: =(mok mak)
|
||||||
[cag nub]
|
[cag nub]
|
||||||
=^ =tube nub (get-cast mok mak)
|
=^ =tube nub (build-tube mok mak)
|
||||||
~| error-running-cast+[path mok mak]
|
~| error-running-cast+[path mok mak]
|
||||||
:_(nub [mak (tube q.cag)])
|
:_(nub [mak (tube q.cag)])
|
||||||
::
|
::
|
||||||
@ -746,14 +790,14 @@
|
|||||||
=+ ;;(dif=(urge cord) q.diff)
|
=+ ;;(dif=(urge cord) q.diff)
|
||||||
=/ new=@t (of-wain:format (lurk:differ txt dif))
|
=/ new=@t (of-wain:format (lurk:differ txt dif))
|
||||||
:_(nub [%hoon !>(new)])
|
:_(nub [%hoon !>(new)])
|
||||||
=^ dys=dais nub (get-mark p.old)
|
=^ dys=dais nub (build-dais p.old)
|
||||||
=^ syd=dais nub (get-mark p.diff)
|
=^ syd=dais nub (build-dais p.diff)
|
||||||
:_(nub [p.old (~(pact dys (vale:dys q.old)) (vale:syd q.diff))])
|
:_(nub [p.old (~(pact dys (vale:dys q.old)) (vale:syd q.diff))])
|
||||||
::
|
::
|
||||||
++ prelude
|
++ prelude
|
||||||
|= =path
|
|= =path
|
||||||
^- vase
|
^- vase
|
||||||
=^ cag=cage nub (get-value path)
|
=^ cag=cage nub (read-file path)
|
||||||
?> =(%hoon p.cag)
|
?> =(%hoon p.cag)
|
||||||
=/ tex=tape (trip !<(@t q.cag))
|
=/ tex=tape (trip !<(@t q.cag))
|
||||||
=/ =pile (parse-pile path tex)
|
=/ =pile (parse-pile path tex)
|
||||||
@ -765,7 +809,7 @@
|
|||||||
|= =path
|
|= =path
|
||||||
^- [vase state]
|
^- [vase state]
|
||||||
~| %error-building^path
|
~| %error-building^path
|
||||||
?^ got=(~(get by vases.cache.nub) path)
|
?^ got=(~(get by files.cache.nub) path)
|
||||||
=? stack.nub ?=(^ stack.nub)
|
=? stack.nub ?=(^ stack.nub)
|
||||||
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
stack.nub(i (~(uni in i.stack.nub) dez.u.got))
|
||||||
[res.u.got nub]
|
[res.u.got nub]
|
||||||
@ -773,13 +817,13 @@
|
|||||||
~|(cycle+file+path^stack.nub !!)
|
~|(cycle+file+path^stack.nub !!)
|
||||||
=. cycle.nub (~(put in cycle.nub) file+path)
|
=. cycle.nub (~(put in cycle.nub) file+path)
|
||||||
=. stack.nub [(sy path ~) stack.nub]
|
=. stack.nub [(sy path ~) stack.nub]
|
||||||
=^ cag=cage nub (get-value path)
|
=^ cag=cage nub (read-file path)
|
||||||
?> =(%hoon p.cag)
|
?> =(%hoon p.cag)
|
||||||
=/ tex=tape (trip !<(@t q.cag))
|
=/ tex=tape (trip !<(@t q.cag))
|
||||||
=/ =pile (parse-pile path tex)
|
=/ =pile (parse-pile path tex)
|
||||||
=^ res=vase nub (run-pile pile)
|
=^ res=vase nub (run-pile pile)
|
||||||
=^ top stack.nub pop-stack
|
=^ top stack.nub pop-stack
|
||||||
=. vases.cache.nub (~(put by vases.cache.nub) path [res top])
|
=. files.cache.nub (~(put by files.cache.nub) path [res top])
|
||||||
[res nub]
|
[res nub]
|
||||||
::
|
::
|
||||||
++ run-pile
|
++ run-pile
|
||||||
@ -787,6 +831,8 @@
|
|||||||
=^ sut=vase nub (run-tauts bud %sur sur.pile)
|
=^ sut=vase nub (run-tauts bud %sur sur.pile)
|
||||||
=^ sut=vase nub (run-tauts sut %lib lib.pile)
|
=^ sut=vase nub (run-tauts sut %lib lib.pile)
|
||||||
=^ sut=vase nub (run-raw sut raw.pile)
|
=^ sut=vase nub (run-raw sut raw.pile)
|
||||||
|
=^ sut=vase nub (run-maz sut maz.pile)
|
||||||
|
=^ sut=vase nub (run-caz sut caz.pile)
|
||||||
=^ sut=vase nub (run-bar sut bar.pile)
|
=^ sut=vase nub (run-bar sut bar.pile)
|
||||||
=/ res=vase (road |.((slap sut hoon.pile)))
|
=/ res=vase (road |.((slap sut hoon.pile)))
|
||||||
[res nub]
|
[res nub]
|
||||||
@ -807,75 +853,59 @@
|
|||||||
++ pile-rule
|
++ pile-rule
|
||||||
|= pax=path
|
|= pax=path
|
||||||
%- full
|
%- full
|
||||||
%+ ifix [gay gay]
|
%+ ifix
|
||||||
%+ cook |=(pile +<)
|
:_ gay
|
||||||
;~ pfix
|
|
||||||
:: parse optional /? and ignore
|
:: parse optional /? and ignore
|
||||||
::
|
::
|
||||||
;~ pose
|
;~(plug gay (punt ;~(plug fas wut gap dem gap)))
|
||||||
(cold ~ ;~(plug fas wut gap dem gap))
|
|^
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
|
||||||
;~ plug
|
;~ plug
|
||||||
;~ pose
|
%+ cook (bake zing (list (list taut)))
|
||||||
;~ sfix
|
%+ rune hep
|
||||||
%+ cook |=((list (list taut)) (zing +<))
|
|
||||||
%+ more gap
|
|
||||||
;~ pfix ;~(plug fas hep gap)
|
|
||||||
(most ;~(plug com gaw) taut-rule)
|
(most ;~(plug com gaw) taut-rule)
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
;~ pose
|
%+ cook (bake zing (list (list taut)))
|
||||||
;~ sfix
|
%+ rune lus
|
||||||
%+ cook |=((list (list taut)) (zing +<))
|
|
||||||
%+ more gap
|
|
||||||
;~ pfix ;~(plug fas lus gap)
|
|
||||||
(most ;~(plug com gaw) taut-rule)
|
(most ;~(plug com gaw) taut-rule)
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
;~ pose
|
%+ rune tis
|
||||||
;~ sfix
|
;~(plug sym ;~(pfix gap fas (more fas urs:ab)))
|
||||||
%+ cook |=((list [face=term =path]) +<)
|
|
||||||
%+ more gap
|
|
||||||
;~ pfix ;~(plug fas tis gap)
|
|
||||||
%+ cook |=([term path] +<)
|
|
||||||
;~(plug sym ;~(pfix ;~(plug gap fas) (more fas urs:ab)))
|
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
;~ pose
|
%+ rune cen
|
||||||
;~ sfix
|
;~(plug sym ;~(pfix gap ;~(pfix cen sym)))
|
||||||
%+ cook |=((list [face=term =mark =path]) +<)
|
::
|
||||||
%+ more gap
|
%+ rune buc
|
||||||
;~ pfix ;~(plug fas tar gap)
|
;~ (glue gap)
|
||||||
%+ cook |=([term mark path] +<)
|
|
||||||
;~ plug
|
|
||||||
sym
|
sym
|
||||||
;~(pfix ;~(plug gap cen) sym)
|
;~(pfix cen sym)
|
||||||
;~(pfix ;~(plug gap fas) (more fas urs:ab))
|
;~(pfix cen sym)
|
||||||
==
|
|
||||||
==
|
|
||||||
gap
|
|
||||||
==
|
|
||||||
(easy ~)
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%+ cook |=(huz=(list hoon) `hoon`tssg+huz)
|
%+ rune tar
|
||||||
|
;~ (glue gap)
|
||||||
|
sym
|
||||||
|
;~(pfix cen sym)
|
||||||
|
;~(pfix fas (more fas urs:ab))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%+ stag %tssg
|
||||||
(most gap tall:(vang & pax))
|
(most gap tall:(vang & pax))
|
||||||
==
|
==
|
||||||
==
|
::
|
||||||
|
++ pant
|
||||||
|
|* fel=^rule
|
||||||
|
;~(pose fel (easy ~))
|
||||||
|
::
|
||||||
|
++ mast
|
||||||
|
|* [bus=^rule fel=^rule]
|
||||||
|
;~(sfix (more bus fel) bus)
|
||||||
|
::
|
||||||
|
++ rune
|
||||||
|
|* [bus=^rule fel=^rule]
|
||||||
|
%- pant
|
||||||
|
%+ mast gap
|
||||||
|
;~(pfix fas bus gap fel)
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ taut-rule
|
++ taut-rule
|
||||||
%+ cook |=(taut +<)
|
%+ cook |=(taut +<)
|
||||||
@ -901,6 +931,22 @@
|
|||||||
=. p.pin [%face face.i.raw p.pin]
|
=. p.pin [%face face.i.raw p.pin]
|
||||||
$(sut (slop pin sut), raw t.raw)
|
$(sut (slop pin sut), raw t.raw)
|
||||||
::
|
::
|
||||||
|
++ run-maz
|
||||||
|
|= [sut=vase maz=(list [face=term =mark])]
|
||||||
|
^- [vase state]
|
||||||
|
?~ maz [sut nub]
|
||||||
|
=^ pin=vase nub (build-nave mark.i.maz)
|
||||||
|
=. p.pin [%face face.i.maz p.pin]
|
||||||
|
$(sut (slop pin sut), maz t.maz)
|
||||||
|
::
|
||||||
|
++ run-caz
|
||||||
|
|= [sut=vase caz=(list [face=term =mars])]
|
||||||
|
^- [vase state]
|
||||||
|
?~ caz [sut nub]
|
||||||
|
=^ pin=vase nub (build-cast mars.i.caz)
|
||||||
|
=. p.pin [%face face.i.caz p.pin]
|
||||||
|
$(sut (slop pin sut), caz t.caz)
|
||||||
|
::
|
||||||
++ run-bar
|
++ run-bar
|
||||||
|= [sut=vase bar=(list [face=term =mark =path])]
|
|= [sut=vase bar=(list [face=term =mark =path])]
|
||||||
^- [vase state]
|
^- [vase state]
|
||||||
@ -1527,9 +1573,11 @@
|
|||||||
%+ turn (tail (spud pux)) :: lose leading '/'
|
%+ turn (tail (spud pux)) :: lose leading '/'
|
||||||
|=(c=@tD `@tD`?:(=('/' c) '-' c)) :: convert '/' to '-'
|
|=(c=@tD `@tD`?:(=('/' c) '-' c)) :: convert '/' to '-'
|
||||||
::
|
::
|
||||||
:* ((invalidate path vase) vases.ford-cache invalid)
|
:* ((invalidate path vase) files.ford-cache invalid)
|
||||||
|
((invalidate mark vase) naves.ford-cache invalid)
|
||||||
((invalidate mark dais) marks.ford-cache invalid)
|
((invalidate mark dais) marks.ford-cache invalid)
|
||||||
((invalidate mars tube) casts.ford-cache invalid)
|
((invalidate mars vase) casts.ford-cache invalid)
|
||||||
|
((invalidate mars tube) tubes.ford-cache invalid)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ invalidate
|
++ invalidate
|
||||||
@ -1640,24 +1688,26 @@
|
|||||||
::
|
::
|
||||||
++ checkout-changes
|
++ checkout-changes
|
||||||
|= [=ford=args:ford:fusion changes=(map path (each page lobe))]
|
|= [=ford=args:ford:fusion changes=(map path (each page lobe))]
|
||||||
=/ cans=(list [=path change=(each page lobe)]) ~(tap by changes)
|
^- [(map path [=lobe =cage]) ford-cache]
|
||||||
|- ^- [(map path [=lobe =cage]) ford-cache]
|
%+ roll `(list [path (each page lobe)])`~(tap by changes)
|
||||||
?~ cans
|
|= $: [=path change=(each page lobe)]
|
||||||
[~ ford-cache.ford-args]
|
[built=(map path [lobe cage]) cache=_ford-cache.ford-args]
|
||||||
|
==
|
||||||
|
^+ [built cache]
|
||||||
|
=. ford-cache.ford-args cache
|
||||||
=^ cage ford-cache.ford-args
|
=^ cage ford-cache.ford-args
|
||||||
:: ~> %slog.[0 leaf+"clay: validating {(spud path.i.cans)}"]
|
:: ~> %slog.[0 leaf/"clay: validating {(spud path)}"]
|
||||||
%- wrap:fusion
|
%- wrap:fusion
|
||||||
(get-value:(ford:fusion ford-args) path.i.cans)
|
(read-file:(ford:fusion ford-args) path)
|
||||||
=/ =lobe
|
=/ =lobe
|
||||||
?- -.change.i.cans
|
?- -.change
|
||||||
%| p.change.i.cans
|
%| p.change
|
||||||
:: Don't use p.change.i.cans because that's before casting to
|
:: Don't use p.change.i.cans because that's before casting to
|
||||||
:: the correct mark.
|
:: the correct mark.
|
||||||
::
|
::
|
||||||
%& (page-to-lobe [p q.q]:cage)
|
%& (page-to-lobe [p q.q]:cage)
|
||||||
==
|
==
|
||||||
=^ so-far ford-cache.ford-args $(cans t.cans)
|
[(~(put by built) path [lobe cage]) ford-cache.ford-args]
|
||||||
[(~(put by so-far) path.i.cans lobe cage) ford-cache.ford-args]
|
|
||||||
::
|
::
|
||||||
:: Update ankh
|
:: Update ankh
|
||||||
::
|
::
|
||||||
@ -2235,7 +2285,7 @@
|
|||||||
^- dais
|
^- dais
|
||||||
=^ =dais fod.dom
|
=^ =dais fod.dom
|
||||||
%- wrap:fusion
|
%- wrap:fusion
|
||||||
(get-mark:(ford:fusion static-ford-args) mark)
|
(build-dais:(ford:fusion static-ford-args) mark)
|
||||||
dais
|
dais
|
||||||
::
|
::
|
||||||
:: Diff two files on bob-desk
|
:: Diff two files on bob-desk
|
||||||
@ -2665,6 +2715,8 @@
|
|||||||
%b ~| %i-guess-you-ought-to-build-your-own-marks !!
|
%b ~| %i-guess-you-ought-to-build-your-own-marks !!
|
||||||
%c ~| %casts-should-be-compiled-on-your-own-ship !!
|
%c ~| %casts-should-be-compiled-on-your-own-ship !!
|
||||||
%d ~| %totally-temporary-error-please-replace-me !!
|
%d ~| %totally-temporary-error-please-replace-me !!
|
||||||
|
%e ~| %yes-naves-also-shouldnt-cross-the-network !!
|
||||||
|
%f ~| %even-static-casts-should-be-built-locally !!
|
||||||
%p ~| %requesting-foreign-permissions-is-invalid !!
|
%p ~| %requesting-foreign-permissions-is-invalid !!
|
||||||
%r ~| %no-cages-please-they-are-just-way-too-big !!
|
%r ~| %no-cages-please-they-are-just-way-too-big !!
|
||||||
%s ~| %please-dont-get-your-takos-over-a-network !!
|
%s ~| %please-dont-get-your-takos-over-a-network !!
|
||||||
@ -3418,7 +3470,7 @@
|
|||||||
^- [(unit (unit (each cage lobe))) ford-cache]
|
^- [(unit (unit (each cage lobe))) ford-cache]
|
||||||
?. =(aeon let.dom)
|
?. =(aeon let.dom)
|
||||||
[~ fod.dom]
|
[~ fod.dom]
|
||||||
=/ cached=(unit [=vase *]) (~(get by vases.fod.dom) path)
|
=/ cached=(unit [=vase *]) (~(get by files.fod.dom) path)
|
||||||
?^ cached
|
?^ cached
|
||||||
:_(fod.dom [~ ~ %& %vase !>(vase.u.cached)])
|
:_(fod.dom [~ ~ %& %vase !>(vase.u.cached)])
|
||||||
=/ x (read-x aeon path)
|
=/ x (read-x aeon path)
|
||||||
@ -3447,7 +3499,7 @@
|
|||||||
:_(fod.dom [~ ~ %& %dais !>(dais.u.cached)])
|
:_(fod.dom [~ ~ %& %dais !>(dais.u.cached)])
|
||||||
=^ =dais fod.dom
|
=^ =dais fod.dom
|
||||||
%- wrap:fusion
|
%- wrap:fusion
|
||||||
(get-mark:(ford:fusion static-ford-args) i.path)
|
(build-dais:(ford:fusion static-ford-args) i.path)
|
||||||
:_(fod.dom [~ ~ %& %dais !>(dais)])
|
:_(fod.dom [~ ~ %& %dais !>(dais)])
|
||||||
::
|
::
|
||||||
++ read-c
|
++ read-c
|
||||||
@ -3458,14 +3510,46 @@
|
|||||||
[~ fod.dom]
|
[~ fod.dom]
|
||||||
?. ?=([@ @ ~] path)
|
?. ?=([@ @ ~] path)
|
||||||
[[~ ~] fod.dom]
|
[[~ ~] fod.dom]
|
||||||
=/ cached=(unit [=tube *]) (~(get by casts.fod.dom) [i i.t]:path)
|
=/ cached=(unit [=tube *]) (~(get by tubes.fod.dom) [i i.t]:path)
|
||||||
?^ cached
|
?^ cached
|
||||||
:_(fod.dom [~ ~ %& %tube !>(tube.u.cached)])
|
:_(fod.dom [~ ~ %& %tube !>(tube.u.cached)])
|
||||||
=^ =tube fod.dom
|
=^ =tube fod.dom
|
||||||
%- wrap:fusion
|
%- wrap:fusion
|
||||||
(get-cast:(ford:fusion static-ford-args) [i i.t]:path)
|
(build-tube:(ford:fusion static-ford-args) [i i.t]:path)
|
||||||
:_(fod.dom [~ ~ %& %tube !>(tube)])
|
:_(fod.dom [~ ~ %& %tube !>(tube)])
|
||||||
::
|
::
|
||||||
|
++ read-e
|
||||||
|
!.
|
||||||
|
|= [=aeon =path]
|
||||||
|
^- [(unit (unit (each cage lobe))) ford-cache]
|
||||||
|
?. =(aeon let.dom)
|
||||||
|
[~ fod.dom]
|
||||||
|
?. ?=([@ ~] path)
|
||||||
|
[[~ ~] fod.dom]
|
||||||
|
=/ cached=(unit [=vase *]) (~(get by naves.fod.dom) i.path)
|
||||||
|
?^ cached
|
||||||
|
:_(fod.dom [~ ~ %& %nave !>(vase.u.cached)])
|
||||||
|
=^ =vase fod.dom
|
||||||
|
%- wrap:fusion
|
||||||
|
(build-nave:(ford:fusion static-ford-args) i.path)
|
||||||
|
:_(fod.dom [~ ~ %& %nave !>(vase)])
|
||||||
|
::
|
||||||
|
++ read-f
|
||||||
|
!.
|
||||||
|
|= [=aeon =path]
|
||||||
|
^- [(unit (unit (each cage lobe))) ford-cache]
|
||||||
|
?. =(aeon let.dom)
|
||||||
|
[~ fod.dom]
|
||||||
|
?. ?=([@ @ ~] path)
|
||||||
|
[[~ ~] fod.dom]
|
||||||
|
=/ cached=(unit [=vase *]) (~(get by casts.fod.dom) [i i.t]:path)
|
||||||
|
?^ cached
|
||||||
|
:_(fod.dom [~ ~ %& %cast vase.u.cached])
|
||||||
|
=^ =vase fod.dom
|
||||||
|
%- wrap:fusion
|
||||||
|
(build-cast:(ford:fusion static-ford-args) [i i.t]:path)
|
||||||
|
:_(fod.dom [~ ~ %& %cast vase])
|
||||||
|
::
|
||||||
:: Gets the permissions that apply to a particular node.
|
:: Gets the permissions that apply to a particular node.
|
||||||
::
|
::
|
||||||
:: If the node has no permissions of its own, we use its parent's.
|
:: If the node has no permissions of its own, we use its parent's.
|
||||||
@ -3810,7 +3894,8 @@
|
|||||||
:: virtualize to catch and produce deterministic failures
|
:: virtualize to catch and produce deterministic failures
|
||||||
::
|
::
|
||||||
!.
|
!.
|
||||||
=- ?:(?=(%& -<) p.- ((slog p.-) [[~ ~] fod]))
|
=- ?: ?=(%& -<) p.-
|
||||||
|
((slog leaf+"gall: read-at-aeon fail {<mun>}" p.-) [[~ ~] fod])
|
||||||
%- mule |.
|
%- mule |.
|
||||||
?- care.mun
|
?- care.mun
|
||||||
%d
|
%d
|
||||||
@ -3826,6 +3911,8 @@
|
|||||||
%a (read-a yon path.mun)
|
%a (read-a yon path.mun)
|
||||||
%b (read-b yon path.mun)
|
%b (read-b yon path.mun)
|
||||||
%c (read-c yon path.mun)
|
%c (read-c yon path.mun)
|
||||||
|
%e (read-e yon path.mun)
|
||||||
|
%f (read-f yon path.mun)
|
||||||
%p :_(fod (read-p path.mun))
|
%p :_(fod (read-p path.mun))
|
||||||
%r :_(fod (bind (read-r yon path.mun) (lift |=(a=cage [%& a]))))
|
%r :_(fod (bind (read-r yon path.mun) (lift |=(a=cage [%& a]))))
|
||||||
%s :_(fod (bind (read-s yon path.mun) (lift |=(a=cage [%& a]))))
|
%s :_(fod (bind (read-s yon path.mun) (lift |=(a=cage [%& a]))))
|
||||||
@ -3871,7 +3958,7 @@
|
|||||||
::
|
::
|
||||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
=| :: instrument state
|
=| :: instrument state
|
||||||
$: ver=%6 :: vane version
|
$: ver=%7 :: vane version
|
||||||
ruf=raft :: revision tree
|
ruf=raft :: revision tree
|
||||||
== ::
|
== ::
|
||||||
|= [now=@da eny=@uvJ rof=roof] :: current invocation
|
|= [now=@da eny=@uvJ rof=roof] :: current invocation
|
||||||
@ -4113,8 +4200,77 @@
|
|||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ load
|
++ load
|
||||||
|= old=[%6 raft]
|
=> |%
|
||||||
..^$(ruf +.old)
|
+$ raft-any
|
||||||
|
$% [%7 raft-7]
|
||||||
|
[%6 raft-6]
|
||||||
|
==
|
||||||
|
+$ raft-7 raft
|
||||||
|
+$ dojo-7 dojo
|
||||||
|
+$ ford-cache-7 ford-cache
|
||||||
|
+$ raft-6
|
||||||
|
$: rom=room-6 :: domestic
|
||||||
|
hoy=(map ship rung-6) :: foreign
|
||||||
|
ran=rang :: hashes
|
||||||
|
mon=(map term beam) :: mount points
|
||||||
|
hez=(unit duct) :: sync duct
|
||||||
|
cez=(map @ta crew) :: permission groups
|
||||||
|
pud=(unit [=desk =yoki]) :: pending update
|
||||||
|
== ::
|
||||||
|
+$ room-6 [hun=duct dos=(map desk dojo-6)]
|
||||||
|
+$ dojo-6
|
||||||
|
$: qyx=cult :: subscribers
|
||||||
|
dom=dome-6 :: desk state
|
||||||
|
per=regs :: read perms per path
|
||||||
|
pew=regs :: write perms per path
|
||||||
|
==
|
||||||
|
+$ dome-6
|
||||||
|
$: ank=ankh :: state
|
||||||
|
let=aeon :: top id
|
||||||
|
hit=(map aeon tako) :: versions by id
|
||||||
|
lab=(map @tas aeon) :: labels
|
||||||
|
mim=(map path mime) :: mime cache
|
||||||
|
fod=ford-cache-6 :: ford cache
|
||||||
|
fer=(unit reef-cache) :: reef cache
|
||||||
|
==
|
||||||
|
+$ rung-6
|
||||||
|
$: rus=(map desk rede-6)
|
||||||
|
==
|
||||||
|
+$ rede-6
|
||||||
|
$: lim=@da
|
||||||
|
ref=(unit rind)
|
||||||
|
qyx=cult
|
||||||
|
dom=dome-6
|
||||||
|
per=regs
|
||||||
|
pew=regs
|
||||||
|
==
|
||||||
|
+$ ford-cache-6 * :: discard old cache
|
||||||
|
--
|
||||||
|
|= old=raft-any
|
||||||
|
|^
|
||||||
|
=? old ?=(%6 -.old) 7+(raft-6-to-7 +.old)
|
||||||
|
?> ?=(%7 -.old)
|
||||||
|
..^^$(ruf +.old)
|
||||||
|
:: +raft-6-to-7: delete stale ford caches (they could all be invalid)
|
||||||
|
::
|
||||||
|
++ raft-6-to-7
|
||||||
|
|= raf=raft-6
|
||||||
|
^- raft-7
|
||||||
|
%= raf
|
||||||
|
dos.rom
|
||||||
|
%- ~(run by dos.rom.raf)
|
||||||
|
|= doj=dojo-6
|
||||||
|
^- dojo-7
|
||||||
|
doj(fod.dom *ford-cache-7)
|
||||||
|
::
|
||||||
|
hoy
|
||||||
|
%- ~(run by hoy.raf)
|
||||||
|
|= =rung-6
|
||||||
|
%- ~(run by rus.rung-6)
|
||||||
|
|= =rede-6
|
||||||
|
rede-6(dom dom.rede-6(fod *ford-cache-7))
|
||||||
|
==
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ scry :: inspect
|
++ scry :: inspect
|
||||||
^- roon
|
^- roon
|
||||||
@ -4164,7 +4320,7 @@
|
|||||||
dos.rom
|
dos.rom
|
||||||
%- ~(run by dos.rom.ruf)
|
%- ~(run by dos.rom.ruf)
|
||||||
|= =dojo
|
|= =dojo
|
||||||
dojo(fod.dom [~ ~ ~])
|
dojo(fod.dom [~ ~ ~ ~ ~])
|
||||||
::
|
::
|
||||||
hoy
|
hoy
|
||||||
%- ~(run by hoy.ruf)
|
%- ~(run by hoy.ruf)
|
||||||
@ -4173,7 +4329,7 @@
|
|||||||
rus
|
rus
|
||||||
%- ~(run by rus.rung)
|
%- ~(run by rus.rung)
|
||||||
|= =rede
|
|= =rede
|
||||||
rede(fod.dom [~ ~ ~])
|
rede(fod.dom [~ ~ ~ ~ ~])
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
@ -4348,9 +4504,11 @@
|
|||||||
:+ desk %|
|
:+ desk %|
|
||||||
:~ ankh+&+ank.dom.dojo
|
:~ ankh+&+ank.dom.dojo
|
||||||
mime+&+mim.dom.dojo
|
mime+&+mim.dom.dojo
|
||||||
ford-vases+&+vases.fod.dom.dojo
|
ford-files+&+files.fod.dom.dojo
|
||||||
|
ford-naves+&+naves.fod.dom.dojo
|
||||||
ford-marks+&+marks.fod.dom.dojo
|
ford-marks+&+marks.fod.dom.dojo
|
||||||
ford-casts+&+casts.fod.dom.dojo
|
ford-casts+&+casts.fod.dom.dojo
|
||||||
|
ford-tubes+&+tubes.fod.dom.dojo
|
||||||
==
|
==
|
||||||
:~ domestic+|+domestic
|
:~ domestic+|+domestic
|
||||||
foreign+&+hoy.ruf
|
foreign+&+hoy.ruf
|
||||||
|
@ -680,12 +680,9 @@
|
|||||||
:: note this should only happen on reverse bones, so only facts
|
:: note this should only happen on reverse bones, so only facts
|
||||||
:: and kicks
|
:: and kicks
|
||||||
::
|
::
|
||||||
=/ sys-wire [%sys wire]
|
|
||||||
:: TODO: %drip %kick so app crash can't kill the remote %pull
|
:: TODO: %drip %kick so app crash can't kill the remote %pull
|
||||||
::
|
::
|
||||||
=/ =ames-request-all [%0 %u ~]
|
=. mo-core (mo-send-foreign-request ship foreign-agent %leave ~)
|
||||||
=. mo-core
|
|
||||||
(mo-pass sys-wire %a %plea ship %g /ge/[foreign-agent] ames-request-all)
|
|
||||||
=. mo-core (mo-give %unto %kick ~)
|
=. mo-core (mo-give %unto %kick ~)
|
||||||
mo-core
|
mo-core
|
||||||
==
|
==
|
||||||
@ -942,15 +939,13 @@
|
|||||||
=/ sky (rof ~ %cb [our %home case] /[mark.ames-response])
|
=/ sky (rof ~ %cb [our %home case] /[mark.ames-response])
|
||||||
?- sky
|
?- sky
|
||||||
?(~ [~ ~])
|
?(~ [~ ~])
|
||||||
=/ ror "gall: ames mark fail {<mark.ames-response>}"
|
(mean leaf+"gall: ames mark fail {<mark.ames-response>}" ~)
|
||||||
(mo-give %done `vale+[leaf+ror]~)
|
|
||||||
::
|
::
|
||||||
[~ ~ *]
|
[~ ~ *]
|
||||||
=+ !<(=dais:clay q.u.u.sky)
|
=+ !<(=dais:clay q.u.u.sky)
|
||||||
=/ res (mule |.((vale:dais noun.ames-response)))
|
=/ res (mule |.((vale:dais noun.ames-response)))
|
||||||
?: ?=(%| -.res)
|
?: ?=(%| -.res)
|
||||||
=/ ror "gall: ames vale fail {<mark.deal>}"
|
(mean leaf+"gall: ames vale fail {<mark.ames-response>}" p.res)
|
||||||
(mo-give %done `vale+[leaf+ror p.res])
|
|
||||||
=. mo-core
|
=. mo-core
|
||||||
%+ mo-pass /nowhere
|
%+ mo-pass /nowhere
|
||||||
[%c %warp our %home ~ %sing %b case /[mark.ames-response]]
|
[%c %warp our %home ~ %sing %b case /[mark.ames-response]]
|
||||||
|
@ -3297,11 +3297,14 @@
|
|||||||
%- flop
|
%- flop
|
||||||
|- ^- ^tape
|
|- ^- ^tape
|
||||||
?:(=(0 a) ~ [(add '0' (mod a 10)) $(a (div a 10))])
|
?:(=(0 a) ~ [(add '0' (mod a 10)) $(a (div a 10))])
|
||||||
|
:: :: ++sect:enjs:format
|
||||||
|
++ sect :: s timestamp
|
||||||
|
|= a=^time
|
||||||
|
(numb (unt:chrono:userlib a))
|
||||||
:: :: ++time:enjs:format
|
:: :: ++time:enjs:format
|
||||||
++ time :: ms timestamp
|
++ time :: ms timestamp
|
||||||
|= a=^time
|
|= a=^time
|
||||||
=- (numb (div (mul - 1.000) ~s1))
|
(numb (unm:chrono:userlib a))
|
||||||
(add (div ~s1 2.000) (sub a ~1970.1.1))
|
|
||||||
:: :: ++path:enjs:format
|
:: :: ++path:enjs:format
|
||||||
++ path :: string from path
|
++ path :: string from path
|
||||||
|= a=^path
|
|= a=^path
|
||||||
@ -3365,10 +3368,10 @@
|
|||||||
(poq (wit jon))
|
(poq (wit jon))
|
||||||
:: :: ++di:dejs:format
|
:: :: ++di:dejs:format
|
||||||
++ di :: millisecond date
|
++ di :: millisecond date
|
||||||
%+ cu
|
(cu from-unix-ms:chrono:userlib ni)
|
||||||
|= a=@u ^- @da
|
:: :: ++du:dejs:format
|
||||||
(add ~1970.1.1 (div (mul ~s1 a) 1.000))
|
++ du :: second date
|
||||||
ni
|
(cu from-unix:chrono:userlib ni)
|
||||||
:: :: ++mu:dejs:format
|
:: :: ++mu:dejs:format
|
||||||
++ mu :: true unit
|
++ mu :: true unit
|
||||||
|* wit=fist
|
|* wit=fist
|
||||||
@ -3578,10 +3581,7 @@
|
|||||||
(bind (stud:chrono:userlib p.jon) |=(a=date (year a)))
|
(bind (stud:chrono:userlib p.jon) |=(a=date (year a)))
|
||||||
::
|
::
|
||||||
++ di :: millisecond date
|
++ di :: millisecond date
|
||||||
%+ cu
|
(cu from-unix-ms:chrono:userlib ni)
|
||||||
|= a=@u ^- @da
|
|
||||||
(add ~1970.1.1 (div (mul ~s1 a) 1.000))
|
|
||||||
ni
|
|
||||||
::
|
::
|
||||||
++ mu :: true unit
|
++ mu :: true unit
|
||||||
|* wit=fist
|
|* wit=fist
|
||||||
@ -5230,55 +5230,47 @@
|
|||||||
=/ acc [stop=`?`%.n state=state]
|
=/ acc [stop=`?`%.n state=state]
|
||||||
=< abet =< main
|
=< abet =< main
|
||||||
|%
|
|%
|
||||||
|
++ this .
|
||||||
++ abet [state.acc a]
|
++ abet [state.acc a]
|
||||||
:: +main: main recursive loop; performs a partial inorder traversal
|
:: +main: main recursive loop; performs a partial inorder traversal
|
||||||
::
|
::
|
||||||
++ main
|
++ main
|
||||||
^+ .
|
^+ this
|
||||||
:: stop if empty or we've been told to stop
|
:: stop if empty or we've been told to stop
|
||||||
::
|
::
|
||||||
?~ a .
|
?: =(~ a) this
|
||||||
?: stop.acc .
|
?: stop.acc this
|
||||||
:: inorder traversal: left -> node -> right, until .f sets .stop
|
:: inorder traversal: left -> node -> right, until .f sets .stop
|
||||||
::
|
::
|
||||||
=> left
|
=. this left
|
||||||
?: stop.acc .
|
?: stop.acc this
|
||||||
=> node
|
=^ del this node
|
||||||
?: stop.acc .
|
=? this !stop.acc right
|
||||||
right
|
=? a del (nip a)
|
||||||
|
this
|
||||||
:: +node: run .f on .n.a, updating .a, .state, and .stop
|
:: +node: run .f on .n.a, updating .a, .state, and .stop
|
||||||
::
|
::
|
||||||
++ node
|
++ node
|
||||||
^+ .
|
^+ [del=*? this]
|
||||||
:: run .f on node, updating .stop.acc and .state.acc
|
:: run .f on node, updating .stop.acc and .state.acc
|
||||||
::
|
::
|
||||||
=^ res acc
|
|
||||||
?> ?=(^ a)
|
?> ?=(^ a)
|
||||||
(f state.acc n.a)
|
=^ res acc (f state.acc n.a)
|
||||||
:: apply update to .a from .f's product
|
?~ res
|
||||||
::
|
[del=& this]
|
||||||
=. a
|
[del=| this(val.n.a u.res)]
|
||||||
:: if .f requested node deletion, merge and balance .l.a and .r.a
|
|
||||||
::
|
|
||||||
?~ res (nip a)
|
|
||||||
:: we kept the node; replace its .val; order is unchanged
|
|
||||||
::
|
|
||||||
?> ?=(^ a)
|
|
||||||
a(val.n u.res)
|
|
||||||
::
|
|
||||||
..node
|
|
||||||
:: +left: recurse on left subtree, copying mutant back into .l.a
|
:: +left: recurse on left subtree, copying mutant back into .l.a
|
||||||
::
|
::
|
||||||
++ left
|
++ left
|
||||||
^+ .
|
^+ this
|
||||||
?~ a .
|
?~ a this
|
||||||
=/ lef main(a l.a)
|
=/ lef main(a l.a)
|
||||||
lef(a a(l a.lef))
|
lef(a a(l a.lef))
|
||||||
:: +right: recurse on right subtree, copying mutant back into .r.a
|
:: +right: recurse on right subtree, copying mutant back into .r.a
|
||||||
::
|
::
|
||||||
++ right
|
++ right
|
||||||
^+ .
|
^+ this
|
||||||
?~ a .
|
?~ a this
|
||||||
=/ rig main(a r.a)
|
=/ rig main(a r.a)
|
||||||
rig(a a(r a.rig))
|
rig(a a(r a.rig))
|
||||||
--
|
--
|
||||||
@ -5408,13 +5400,20 @@
|
|||||||
:: ::::
|
:: ::::
|
||||||
++ chrono ^?
|
++ chrono ^?
|
||||||
|%
|
|%
|
||||||
:: +from-unix: unix timestamp to @da
|
:: +from-unix: unix seconds to @da
|
||||||
::
|
::
|
||||||
++ from-unix
|
++ from-unix
|
||||||
|= timestamp=@ud
|
|= timestamp=@ud
|
||||||
^- @da
|
^- @da
|
||||||
%+ add ~1970.1.1
|
%+ add ~1970.1.1
|
||||||
(mul timestamp ~s1)
|
(mul timestamp ~s1)
|
||||||
|
:: +from-unix-ms: unix milliseconds to @da
|
||||||
|
::
|
||||||
|
++ from-unix-ms
|
||||||
|
|= timestamp=@ud
|
||||||
|
^- @da
|
||||||
|
%+ add ~1970.1.1
|
||||||
|
(div (mul ~s1 timestamp) 1.000)
|
||||||
:: :: ++dawn:chrono:
|
:: :: ++dawn:chrono:
|
||||||
++ dawn :: Jan 1 weekday
|
++ dawn :: Jan 1 weekday
|
||||||
|= yer=@ud
|
|= yer=@ud
|
||||||
@ -5533,9 +5532,13 @@
|
|||||||
++ dd :: two digits
|
++ dd :: two digits
|
||||||
(bass 10 (stun 2^2 dit))
|
(bass 10 (stun 2^2 dit))
|
||||||
-- ::
|
-- ::
|
||||||
|
:: :: ++unm:chrono:userlib
|
||||||
|
++ unm :: Urbit to Unix ms
|
||||||
|
|= a=@da
|
||||||
|
(div (mul (sub a ~1970.1.1) 1.000) ~s1)
|
||||||
:: :: ++unt:chrono:userlib
|
:: :: ++unt:chrono:userlib
|
||||||
++ unt :: Urbit to Unix time
|
++ unt :: Urbit to Unix time
|
||||||
|= a=@
|
|= a=@da
|
||||||
(div (sub a ~1970.1.1) ~s1)
|
(div (sub a ~1970.1.1) ~s1)
|
||||||
:: :: ++yu:chrono:userlib
|
:: :: ++yu:chrono:userlib
|
||||||
++ yu :: UTC format constants
|
++ yu :: UTC format constants
|
||||||
|
@ -74,13 +74,15 @@
|
|||||||
=. next-timer ~
|
=. next-timer ~
|
||||||
=. this
|
=. this
|
||||||
%- emit-aqua-events
|
%- emit-aqua-events
|
||||||
|
?^ error
|
||||||
|
:: Should pass through errors to aqua, but doesn't
|
||||||
|
::
|
||||||
|
%- (slog leaf+"aqua-behn: timer failed" u.error)
|
||||||
|
~
|
||||||
:_ ~
|
:_ ~
|
||||||
^- aqua-event
|
^- aqua-event
|
||||||
:+ %event who
|
:+ %event who
|
||||||
:- //behn/0v1n.2m9vh
|
[//behn/0v1n.2m9vh [%wake ~]]
|
||||||
?~ error
|
|
||||||
[%wake ~]
|
|
||||||
[%crud %fail u.error]
|
|
||||||
..abet-pe
|
..abet-pe
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
@ -9,5 +9,5 @@
|
|||||||
?~ bem=(de-beam pax)
|
?~ bem=(de-beam pax)
|
||||||
(strand-fail:strand %path-not-beam >pax< ~)
|
(strand-fail:strand %path-not-beam >pax< ~)
|
||||||
=/ =mars:clay [i i.t]:?>(?=([@ @ ~] s.u.bem) s.u.bem)
|
=/ =mars:clay [i i.t]:?>(?=([@ @ ~] s.u.bem) s.u.bem)
|
||||||
;< =tube:clay bind:m (build-cast:strandio -.u.bem mars)
|
;< =vase bind:m (build-cast:strandio -.u.bem mars)
|
||||||
(pure:m !>(tube))
|
(pure:m vase)
|
||||||
|
13
pkg/arvo/ted/build-nave.hoon
Normal file
13
pkg/arvo/ted/build-nave.hoon
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/- spider
|
||||||
|
/+ strandio
|
||||||
|
=, strand=strand:spider
|
||||||
|
^- thread:spider
|
||||||
|
|= arg=vase
|
||||||
|
=/ m (strand ,vase)
|
||||||
|
^- form:m
|
||||||
|
=+ !<([~ pax=path] arg)
|
||||||
|
?~ bem=(de-beam pax)
|
||||||
|
(strand-fail:strand %path-not-beam >pax< ~)
|
||||||
|
=/ =mark (rear s.u.bem)
|
||||||
|
;< =vase bind:m (build-nave:strandio -.u.bem mark)
|
||||||
|
(pure:m vase)
|
13
pkg/arvo/ted/build-tube.hoon
Normal file
13
pkg/arvo/ted/build-tube.hoon
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/- spider
|
||||||
|
/+ strandio
|
||||||
|
=, strand=strand:spider
|
||||||
|
^- thread:spider
|
||||||
|
|= arg=vase
|
||||||
|
=/ m (strand ,vase)
|
||||||
|
^- form:m
|
||||||
|
=+ !<([~ pax=path] arg)
|
||||||
|
?~ bem=(de-beam pax)
|
||||||
|
(strand-fail:strand %path-not-beam >pax< ~)
|
||||||
|
=/ =mars:clay [i i.t]:?>(?=([@ @ ~] s.u.bem) s.u.bem)
|
||||||
|
;< =tube:clay bind:m (build-tube:strandio -.u.bem mars)
|
||||||
|
(pure:m !>(tube))
|
144
pkg/arvo/ted/gcp/get-token.hoon
Normal file
144
pkg/arvo/ted/gcp/get-token.hoon
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
:: Gets a Google Storage access token.
|
||||||
|
::
|
||||||
|
:: This thread produces a pair of [access-key expires-in], where
|
||||||
|
:: access-key is a @t that can be used as a bearer token to talk
|
||||||
|
:: to the GCP Storage API on behalf of some service account, and
|
||||||
|
:: expires-in is a @dr after which the token will stop working and
|
||||||
|
:: need to be refreshed.
|
||||||
|
::
|
||||||
|
:: It expects settings-store to contain relevant fields from
|
||||||
|
:: a GCP service account JSON file, generally as poked by
|
||||||
|
:: sh/poke-gcp-account-json. Specifically, it depends on the
|
||||||
|
:: `token_uri`, `client_email`, `private_key_id`, and `private_key`
|
||||||
|
:: fields. If these fields are not in settings-store at the time
|
||||||
|
:: the thread is run, it will fail.
|
||||||
|
::
|
||||||
|
:: The thread works by first constructing a self-signed JWT using
|
||||||
|
:: the fields in settings-store. Then, it sends this JWT to the
|
||||||
|
:: specified token URI (usually https://oauth2.googleapis.com/token),
|
||||||
|
:: which responds with a bearer token and expiry.
|
||||||
|
::
|
||||||
|
::
|
||||||
|
/- gcp, spider, settings
|
||||||
|
/+ jose, pkcs, primitive-rsa, strandio
|
||||||
|
=, strand=strand:spider
|
||||||
|
=, rsa=primitive-rsa
|
||||||
|
^- thread:spider
|
||||||
|
|^
|
||||||
|
|= *
|
||||||
|
=/ m (strand ,vase)
|
||||||
|
^- form:m
|
||||||
|
;< =bowl:spider bind:m get-bowl:strandio
|
||||||
|
;< iss=@t bind:m (read-setting %client-email)
|
||||||
|
;< =key:rsa bind:m read-private-key
|
||||||
|
;< kid=@t bind:m (read-setting %private-key-id)
|
||||||
|
;< aud=@t bind:m (read-setting %token-uri)
|
||||||
|
=* scope
|
||||||
|
'https://www.googleapis.com/auth/devstorage.read_write'
|
||||||
|
=/ jot=@t
|
||||||
|
(make-jwt key kid iss scope aud now.bowl)
|
||||||
|
;< =token:gcp bind:m
|
||||||
|
(get-access-token jot aud)
|
||||||
|
(pure:m !>(token))
|
||||||
|
::
|
||||||
|
++ read-setting
|
||||||
|
|= key=term
|
||||||
|
=/ m (strand @t) ^- form:m
|
||||||
|
;< has=? bind:m
|
||||||
|
%+ scry:strandio ?
|
||||||
|
/gx/settings-store/has-entry/gcp-store/[key]/noun
|
||||||
|
?. has
|
||||||
|
(strand-fail:strandio (rap 3 %gcp-missing- key ~) ~)
|
||||||
|
;< =data:settings bind:m
|
||||||
|
%+ scry:strandio
|
||||||
|
data:settings
|
||||||
|
/gx/settings-store/entry/gcp-store/[key]/settings-data
|
||||||
|
?> ?=([%entry %s @] data)
|
||||||
|
(pure:m p.val.data)
|
||||||
|
::
|
||||||
|
++ read-private-key
|
||||||
|
=/ m (strand ,key:rsa) ^- form:m
|
||||||
|
;< dat=@t bind:m (read-setting %private-key)
|
||||||
|
%- pure:m
|
||||||
|
%. dat
|
||||||
|
;: cork
|
||||||
|
to-wain:format
|
||||||
|
ring:de:pem:pkcs8:pkcs
|
||||||
|
need
|
||||||
|
==
|
||||||
|
:: construct and return a self-signed JWT issued now, expiring in ~h1.
|
||||||
|
:: TODO: maybe move this into lib/jose/hoon
|
||||||
|
::
|
||||||
|
++ make-jwt
|
||||||
|
|= [=key:rsa kid=@t iss=@t scope=@t aud=@t iat=@da]
|
||||||
|
^- @t
|
||||||
|
=/ job=json
|
||||||
|
=, enjs:format
|
||||||
|
%^ sign:jws:jose key
|
||||||
|
:: the JWT's "header"
|
||||||
|
%: pairs
|
||||||
|
alg+s+'RS256'
|
||||||
|
typ+s+'JWT'
|
||||||
|
kid+s+kid
|
||||||
|
~
|
||||||
|
==
|
||||||
|
:: the JWT's "payload"
|
||||||
|
%: pairs
|
||||||
|
iss+s+iss
|
||||||
|
sub+s+iss :: per g.co, use iss for sub
|
||||||
|
scope+s+scope
|
||||||
|
aud+s+aud
|
||||||
|
iat+(sect iat)
|
||||||
|
exp+(sect (add iat ~h1))
|
||||||
|
~
|
||||||
|
==
|
||||||
|
=/ [pod=@t pad=@t sig=@t]
|
||||||
|
=, dejs:format
|
||||||
|
((ot 'protected'^so 'payload'^so 'signature'^so ~) job)
|
||||||
|
(rap 3 (join '.' `(list @t)`~[pod pad sig]))
|
||||||
|
:: RPC to get an access token. Probably only works with Google.
|
||||||
|
:: Described at:
|
||||||
|
:: https://developers.google.com/identity/protocols/oauth2/service-account
|
||||||
|
::
|
||||||
|
++ get-access-token
|
||||||
|
|= [jot=@t url=@t]
|
||||||
|
=/ m (strand ,token:gcp) ^- form:m
|
||||||
|
;< ~ bind:m
|
||||||
|
%: send-request:strandio
|
||||||
|
method=%'POST'
|
||||||
|
url=url
|
||||||
|
header-list=['Content-Type'^'application/json' ~]
|
||||||
|
^= body
|
||||||
|
%- some %- as-octt:mimes:html
|
||||||
|
%- en-json:html
|
||||||
|
%: pairs:enjs:format
|
||||||
|
:- 'grant_type'
|
||||||
|
s+'urn:ietf:params:oauth:grant-type:jwt-bearer'
|
||||||
|
assertion+s+jot
|
||||||
|
~
|
||||||
|
==
|
||||||
|
==
|
||||||
|
;< rep=client-response:iris bind:m
|
||||||
|
take-client-response:strandio
|
||||||
|
?> ?=(%finished -.rep)
|
||||||
|
?~ full-file.rep
|
||||||
|
(strand-fail:strandio %gcp-no-response ~)
|
||||||
|
=/ body=@t q.data.u.full-file.rep
|
||||||
|
=/ jon=(unit json) (de-json:html body)
|
||||||
|
?~ jon
|
||||||
|
~| body
|
||||||
|
(strand-fail:strandio %gcp-bad-body ~)
|
||||||
|
=* job u.jon
|
||||||
|
~| job
|
||||||
|
=, dejs:format
|
||||||
|
=/ [typ=@t =token:gcp]
|
||||||
|
%. job
|
||||||
|
%: ot
|
||||||
|
'token_type'^so
|
||||||
|
'access_token'^so
|
||||||
|
'expires_in'^(cu |=(a=@ (mul a ~s1)) ni)
|
||||||
|
~
|
||||||
|
==
|
||||||
|
?> =('Bearer' typ)
|
||||||
|
(pure:m token)
|
||||||
|
--
|
49
pkg/arvo/ted/gcp/is-configured.hoon
Normal file
49
pkg/arvo/ted/gcp/is-configured.hoon
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
:: Tells whether GCP Storage appears to be configured.
|
||||||
|
::
|
||||||
|
:: Thread since it needs to be called from Landscape.
|
||||||
|
::
|
||||||
|
::
|
||||||
|
/- gcp, spider, settings
|
||||||
|
/+ strandio
|
||||||
|
=, strand=strand:spider
|
||||||
|
=, enjs:format
|
||||||
|
^- thread:spider
|
||||||
|
|^
|
||||||
|
|= *
|
||||||
|
=/ m (strand ,vase)
|
||||||
|
^- form:m
|
||||||
|
;< has=? bind:m
|
||||||
|
%: has-settings
|
||||||
|
%client-email
|
||||||
|
%private-key
|
||||||
|
%private-key-id
|
||||||
|
%token-uri
|
||||||
|
~
|
||||||
|
==
|
||||||
|
%- pure:m
|
||||||
|
!>
|
||||||
|
%+ frond %gcp-configured
|
||||||
|
b+has
|
||||||
|
::
|
||||||
|
++ has-settings
|
||||||
|
|= set=(list @tas)
|
||||||
|
=/ m (strand ?)
|
||||||
|
^- form:m
|
||||||
|
?~ set
|
||||||
|
(pure:m %.y)
|
||||||
|
;< has=? bind:m (has-setting i.set)
|
||||||
|
?. has
|
||||||
|
(pure:m %.n)
|
||||||
|
;< has=? bind:m (has-settings t.set)
|
||||||
|
(pure:m has)
|
||||||
|
::
|
||||||
|
++ has-setting
|
||||||
|
|= key=@tas
|
||||||
|
=/ m (strand ?)
|
||||||
|
^- form:m
|
||||||
|
;< has=? bind:m
|
||||||
|
%+ scry:strandio ?
|
||||||
|
/gx/settings-store/has-entry/gcp-store/[key]/noun
|
||||||
|
(pure:m has)
|
||||||
|
::
|
||||||
|
--
|
@ -1,4 +1,5 @@
|
|||||||
/- spider, graph-view, graph=graph-store, *metadata-store, *group, *metadata-store
|
/- spider, graph-view, graph=graph-store,
|
||||||
|
met=metadata-store, *group, *metadata-store
|
||||||
/+ strandio, resource
|
/+ strandio, resource
|
||||||
=>
|
=>
|
||||||
|%
|
|%
|
||||||
@ -28,11 +29,11 @@
|
|||||||
::
|
::
|
||||||
++ scry-metadatum
|
++ scry-metadatum
|
||||||
|= rid=resource
|
|= rid=resource
|
||||||
=/ m (strand ,metadata)
|
=/ m (strand ,metadatum:met)
|
||||||
^- form:m
|
^- form:m
|
||||||
=/ enc-path=@t (scot %t (spat (en-path:resource rid)))
|
=/ enc-path=@t (scot %t (spat (en-path:resource rid)))
|
||||||
;< umeta=(unit metadata) bind:m
|
;< umeta=(unit metadatum:met) bind:m
|
||||||
%+ scry:strandio (unit metadata)
|
%+ scry:strandio (unit metadatum:met)
|
||||||
%+ weld /gx/metadata-store/metadata
|
%+ weld /gx/metadata-store/metadata
|
||||||
/[enc-path]/graph/[enc-path]/noun
|
/[enc-path]/graph/[enc-path]/noun
|
||||||
?> ?=(^ umeta)
|
?> ?=(^ umeta)
|
||||||
@ -48,24 +49,25 @@
|
|||||||
;< =group bind:m (scry-group rid.action)
|
;< =group bind:m (scry-group rid.action)
|
||||||
?. hidden.group
|
?. hidden.group
|
||||||
(strand-fail:strandio %bad-request ~)
|
(strand-fail:strandio %bad-request ~)
|
||||||
;< =metadata bind:m (scry-metadatum rid.action)
|
;< =metadatum:met bind:m (scry-metadatum rid.action)
|
||||||
?~ to.action
|
?~ to.action
|
||||||
;< ~ bind:m
|
;< ~ bind:m
|
||||||
%+ poke-our %contact-view
|
%+ poke-our %contact-view
|
||||||
:- %contact-view-action
|
:- %contact-view-action
|
||||||
!>([%groupify rid.action title.metadata description.metadata])
|
!>([%groupify rid.action title.metadatum description.metadatum])
|
||||||
(pure:m !>(~))
|
(pure:m !>(~))
|
||||||
;< new=^group bind:m (scry-group u.to.action)
|
;< new=^group bind:m (scry-group u.to.action)
|
||||||
?< hidden.new
|
?< hidden.new
|
||||||
=/ new-path (en-path:resource u.to.action)
|
|
||||||
=/ app-path (en-path:resource rid.action)
|
|
||||||
=/ add-md=metadata-action
|
|
||||||
[%add new-path graph+app-path metadata]
|
|
||||||
;< ~ bind:m
|
|
||||||
(poke-our %metadata-store metadata-action+!>(add-md))
|
|
||||||
;< ~ bind:m
|
;< ~ bind:m
|
||||||
%+ poke-our %metadata-store
|
%+ poke-our %metadata-store
|
||||||
metadata-action+!>([%remove app-path graph+app-path])
|
:- %metadata-action
|
||||||
|
!> ^- action:met
|
||||||
|
[%add u.to.action [%graph rid.action] metadatum]
|
||||||
|
;< ~ bind:m
|
||||||
|
%+ poke-our %metadata-store
|
||||||
|
:- %metadata-action
|
||||||
|
!> ^- action:met
|
||||||
|
[%remove rid.action [%graph rid.action]]
|
||||||
;< ~ bind:m
|
;< ~ bind:m
|
||||||
(poke-our %group-store %group-update !>([%remove-group rid.action ~]))
|
(poke-our %group-store %group-update !>([%remove-group rid.action ~]))
|
||||||
(pure:m !>(~))
|
(pure:m !>(~))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/- spider, graph=graph-store, *metadata-store, *group, group-store
|
/- spider, graph=graph-store, met=metadata-store, *group, group-store, push-hook
|
||||||
/+ strandio, resource, graph-view
|
/+ strandio, resource, graph-view
|
||||||
=>
|
=>
|
||||||
|%
|
|%
|
||||||
@ -23,17 +23,22 @@
|
|||||||
::
|
::
|
||||||
:: Setup metadata
|
:: Setup metadata
|
||||||
::
|
::
|
||||||
=/ =metadata
|
=/ =metadatum:met
|
||||||
%* . *metadata
|
%* . *metadatum:met
|
||||||
title title
|
title title
|
||||||
description description
|
description description
|
||||||
date-created now.bowl
|
date-created now.bowl
|
||||||
creator our.bowl
|
creator our.bowl
|
||||||
module module
|
module module
|
||||||
==
|
==
|
||||||
=/ act=metadata-action
|
|
||||||
[%add (en-path:resource group) graph+(en-path:resource rid) metadata]
|
|
||||||
;< ~ bind:m (poke-our %metadata-hook %metadata-action !>(act))
|
|
||||||
;< ~ bind:m
|
;< ~ bind:m
|
||||||
(poke-our %metadata-hook %metadata-hook-action !>([%add-owned (en-path:resource group)]))
|
%+ poke-our %metadata-push-hook
|
||||||
|
:- %metadata-action
|
||||||
|
!> ^- action:met
|
||||||
|
[%add group [%graph rid] metadatum]
|
||||||
|
;< ~ bind:m
|
||||||
|
%+ poke-our %metadata-push-hook
|
||||||
|
:- %push-hook-action
|
||||||
|
!> ^- action:push-hook
|
||||||
|
[%add group]
|
||||||
(pure:m !>(~))
|
(pure:m !>(~))
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
/- spider, *metadata-store
|
|
||||||
/+ strandio
|
|
||||||
=, strand=strand:spider
|
|
||||||
^- thread:spider
|
|
||||||
|= arg=vase
|
|
||||||
=/ m (strand ,vase)
|
|
||||||
^- form:m
|
|
||||||
=/ [~ og-path=path ng-path=path] !<([~ path path] arg)
|
|
||||||
;< bol=bowl:spider bind:m get-bowl:strandio
|
|
||||||
|^
|
|
||||||
::
|
|
||||||
=/ og=(unit (set ship)) (scry-for (unit (set ship)) %group-store og-path)
|
|
||||||
?~ og
|
|
||||||
(pure:m !>("no such group: {<og-path>}"))
|
|
||||||
=/ ng=(unit (set ship)) (scry-for (unit (set ship)) %group-store ng-path)
|
|
||||||
?~ ng
|
|
||||||
(pure:m !>("no such group: {<ng-path>}"))
|
|
||||||
::
|
|
||||||
=/ assoc=associations (scry-for associations %metadata-store [%group og-path])
|
|
||||||
=/ assoc-list=(list [[group-path md-resource] metadata]) ~(tap by assoc)
|
|
||||||
::
|
|
||||||
|-
|
|
||||||
=* loop $
|
|
||||||
?~ assoc-list
|
|
||||||
;< ~ bind:m
|
|
||||||
(poke-our:strandio %group-store %group-action !>([%unbundle og-path]))
|
|
||||||
(pure:m !>("done"))
|
|
||||||
=/ [[g-path=group-path res=md-resource] meta=metadata] i.assoc-list
|
|
||||||
?. =(our.bol creator.meta)
|
|
||||||
loop(assoc-list t.assoc-list)
|
|
||||||
?> =(g-path og-path)
|
|
||||||
=/ output=(list card:agent:gall)
|
|
||||||
?+ app-name.res ~
|
|
||||||
::
|
|
||||||
?(%chat %link)
|
|
||||||
%- (slog leaf+"migrating {<app-name.res>} : {<app-path.res>}" ~)
|
|
||||||
:~ :* %pass /poke %agent
|
|
||||||
[our.bol %metadata-hook]
|
|
||||||
%poke %metadata-action
|
|
||||||
!>([%add ng-path res meta])
|
|
||||||
==
|
|
||||||
:* %pass /poke %agent
|
|
||||||
[our.bol %metadata-hook]
|
|
||||||
%poke %metadata-action
|
|
||||||
!>([%remove g-path res])
|
|
||||||
==
|
|
||||||
==
|
|
||||||
%publish
|
|
||||||
%- (slog leaf+"migrating {<app-name.res>} : {<app-path.res>}" ~)
|
|
||||||
=/ book (scry-for notebook %publish [%book app-path.res])
|
|
||||||
?> ?=([@tas @tas ~] app-path.res)
|
|
||||||
:~ :* %pass /poke %agent
|
|
||||||
[our.bol %publish]
|
|
||||||
%poke %publish-action
|
|
||||||
!>
|
|
||||||
:* %edit-book
|
|
||||||
i.t.app-path.res
|
|
||||||
title.book
|
|
||||||
description.book
|
|
||||||
comments.book
|
|
||||||
`[ng-path ~ %.y %.n]
|
|
||||||
==
|
|
||||||
==
|
|
||||||
:* %pass /poke %agent
|
|
||||||
[our.bol %metadata-hook]
|
|
||||||
%poke %metadata-action
|
|
||||||
!>([%remove g-path res])
|
|
||||||
==
|
|
||||||
==
|
|
||||||
==
|
|
||||||
::
|
|
||||||
;< ~ bind:m (send-raw-cards:strandio output)
|
|
||||||
loop(assoc-list t.assoc-list)
|
|
||||||
::
|
|
||||||
++ scry-for
|
|
||||||
|* [mol=mold app=term pax=path]
|
|
||||||
.^ mol
|
|
||||||
%gx
|
|
||||||
(scot %p our.bol)
|
|
||||||
app
|
|
||||||
(scot %da now.bol)
|
|
||||||
(snoc `path`pax %noun)
|
|
||||||
==
|
|
||||||
--
|
|
@ -1,46 +0,0 @@
|
|||||||
/- spider,
|
|
||||||
contact-view,
|
|
||||||
*resource
|
|
||||||
/+ *ph-io, strandio
|
|
||||||
=, strand=strand:spider
|
|
||||||
::
|
|
||||||
^- thread:spider
|
|
||||||
|= vase
|
|
||||||
=/ m (strand ,vase)
|
|
||||||
;< ~ bind:m start-simple
|
|
||||||
;< bol=bowl:spider bind:m get-bowl:strandio
|
|
||||||
::
|
|
||||||
:: group setup
|
|
||||||
:: - ~zod creates an open group
|
|
||||||
:: - ~zod creates and invite-only group, and invites ~bus and ~web
|
|
||||||
:: - ~bus and ~web join the first, but not the second group, to keep
|
|
||||||
:: invite-store populated
|
|
||||||
::
|
|
||||||
=/ group-1=contact-view-action:contact-view
|
|
||||||
:* %create
|
|
||||||
%group-1
|
|
||||||
[%open ~ ~]
|
|
||||||
'Group 1'
|
|
||||||
'this is group 1'
|
|
||||||
==
|
|
||||||
=/ group-2=contact-view-action:contact-view
|
|
||||||
:* %create
|
|
||||||
%group-2
|
|
||||||
[%invite (sy ~bus ~web ~)]
|
|
||||||
'Group 2'
|
|
||||||
'this is group 2'
|
|
||||||
==
|
|
||||||
=/ join=contact-view-action:contact-view [%join ~zod %group-1]
|
|
||||||
;< ~ bind:m (poke-app ~zod %contact-view %contact-view-action group-1)
|
|
||||||
;< ~ bind:m (wait-for-output ~zod ">=")
|
|
||||||
;< ~ bind:m (poke-app ~zod %contact-view %contact-view-action group-2)
|
|
||||||
;< ~ bind:m (wait-for-output ~zod ">=")
|
|
||||||
;< ~ bind:m (sleep ~s10)
|
|
||||||
;< ~ bind:m (poke-app ~bus %contact-view %contact-view-action join)
|
|
||||||
;< ~ bind:m (wait-for-output ~bus ">=")
|
|
||||||
;< ~ bind:m (poke-app ~web %contact-view %contact-view-action join)
|
|
||||||
;< ~ bind:m (wait-for-output ~web ">=")
|
|
||||||
;< ~ bind:m (send-hi ~bus ~zod)
|
|
||||||
;< ~ bind:m (send-hi ~web ~zod)
|
|
||||||
;< ~ bind:m (sleep ~s2)
|
|
||||||
(pure:m *vase)
|
|
@ -1,24 +0,0 @@
|
|||||||
/- spider,
|
|
||||||
contact-view,
|
|
||||||
*resource,
|
|
||||||
group-store
|
|
||||||
/+ *ph-io, strandio
|
|
||||||
=, strand=strand:spider
|
|
||||||
::
|
|
||||||
^- thread:spider
|
|
||||||
|= vase
|
|
||||||
=/ m (strand ,vase)
|
|
||||||
;< ~ bind:m start-simple
|
|
||||||
;< bol=bowl:spider bind:m get-bowl:strandio
|
|
||||||
::
|
|
||||||
=/ join-2=contact-view-action:contact-view [%join ~zod %group-2]
|
|
||||||
=/ add-members-1=action:group-store
|
|
||||||
[%add-members [~zod %group-1] (sy ~def ~ten ~)]
|
|
||||||
=/ add-members-2=action:group-store
|
|
||||||
[%add-members [~zod %group-2] (sy ~def ~ten ~)]
|
|
||||||
;< ~ bind:m (poke-app ~bus %contact-view %contact-view-action join-2)
|
|
||||||
;< ~ bind:m (poke-app ~web %contact-view %contact-view-action join-2)
|
|
||||||
;< ~ bind:m (poke-app ~zod %group-store %group-action add-members-1)
|
|
||||||
;< ~ bind:m (poke-app ~zod %group-store %group-action add-members-2)
|
|
||||||
::
|
|
||||||
(pure:m *vase)
|
|
@ -1,61 +0,0 @@
|
|||||||
/- spider,
|
|
||||||
contact-view,
|
|
||||||
contact-store,
|
|
||||||
group-store,
|
|
||||||
metadata-store,
|
|
||||||
post,
|
|
||||||
graph-store,
|
|
||||||
*resource
|
|
||||||
/+ *ph-io, strandio
|
|
||||||
=, strand=strand:spider
|
|
||||||
::
|
|
||||||
::
|
|
||||||
^- thread:spider
|
|
||||||
|= vase
|
|
||||||
=/ m (strand ,vase)
|
|
||||||
;< ~ bind:m start-simple
|
|
||||||
;< bol=bowl:spider bind:m get-bowl:strandio
|
|
||||||
::
|
|
||||||
:: test metadata import
|
|
||||||
::
|
|
||||||
=/ change-group-1=metadata-action:metadata-store
|
|
||||||
:* %add
|
|
||||||
/ship/~zod/group-1
|
|
||||||
[%contacts /ship/~zod/group-1]
|
|
||||||
'New Group 1 Title'
|
|
||||||
'new description'
|
|
||||||
0x0
|
|
||||||
now.bol
|
|
||||||
~zod
|
|
||||||
'fake'
|
|
||||||
==
|
|
||||||
=/ change-web-book=metadata-action:metadata-store
|
|
||||||
:* %add
|
|
||||||
/ship/~web/graph-3
|
|
||||||
[%graph /ship/~web/graph-3]
|
|
||||||
'New Graph 3 Title'
|
|
||||||
'new description'
|
|
||||||
0x0
|
|
||||||
now.bol
|
|
||||||
~web
|
|
||||||
'fake'
|
|
||||||
==
|
|
||||||
;< ~ bind:m (poke-app ~zod %metadata-hook %metadata-action change-group-1)
|
|
||||||
;< ~ bind:m (sleep ~s5)
|
|
||||||
;< ~ bind:m (poke-app ~web %metadata-hook %metadata-action change-web-book)
|
|
||||||
;< ~ bind:m (sleep ~s5)
|
|
||||||
::
|
|
||||||
:: test contacts import
|
|
||||||
::
|
|
||||||
=/ add-zod=contact-action:contact-store
|
|
||||||
:* %add /ship/~zod/group-1 ~zod
|
|
||||||
'ZOD' '' '' '' '' 0x0 ~
|
|
||||||
==
|
|
||||||
=/ add-bus=contact-action:contact-store
|
|
||||||
:* %add /ship/~zod/group-2 ~bus
|
|
||||||
'BUS' '' '' '' '' 0x0 ~
|
|
||||||
==
|
|
||||||
;< ~ bind:m (poke-app ~zod %contact-hook %contact-action add-zod)
|
|
||||||
;< ~ bind:m (sleep ~s5)
|
|
||||||
;< ~ bind:m (poke-app ~bus %contact-hook %contact-action add-bus)
|
|
||||||
(pure:m *vase)
|
|
@ -1,9 +1,15 @@
|
|||||||
/+ *test
|
/+ *test
|
||||||
/= clay-raw /sys/vane/clay
|
/= clay-raw /sys/vane/clay
|
||||||
/* hello-gen %hoon /gen/hello/hoon
|
/* gen-hello %hoon /gen/hello/hoon
|
||||||
/* strandio-lib %hoon /lib/strandio/hoon
|
/* lib-cram %hoon /lib/cram/hoon
|
||||||
/* strand-lib %hoon /lib/strand/hoon
|
/* lib-strandio %hoon /lib/strandio/hoon
|
||||||
/* spider-sur %hoon /sur/spider/hoon
|
/* lib-strand %hoon /lib/strand/hoon
|
||||||
|
/* sur-spider %hoon /sur/spider/hoon
|
||||||
|
/* mar-html %hoon /mar/html/hoon
|
||||||
|
/* mar-mime %hoon /mar/mime/hoon
|
||||||
|
/* mar-udon %hoon /mar/udon/hoon
|
||||||
|
/* mar-txt %hoon /mar/txt/hoon
|
||||||
|
/* mar-txt-diff %hoon /mar/txt-diff/hoon
|
||||||
::
|
::
|
||||||
!:
|
!:
|
||||||
=, format
|
=, format
|
||||||
@ -14,32 +20,48 @@
|
|||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
++ test-parse-pile ^- tang
|
++ test-parse-pile ^- tang
|
||||||
|
=/ src "."
|
||||||
%+ expect-eq
|
%+ expect-eq
|
||||||
!> ^- pile:fusion
|
!> ^- pile:fusion
|
||||||
:* ~ ~ ~ ~
|
:* ~ ~ ~ ~ ~ ~
|
||||||
tssg+[%dbug [/sur/foo/hoon [[1 1] [1 2]]] [%cnts ~[[%.y 1]] ~]]~
|
tssg+[%dbug [/sur/foo/hoon [[1 1] [1 2]]] [%cnts ~[[%.y 1]] ~]]~
|
||||||
==
|
==
|
||||||
!> (parse-pile:(ford):fusion /sur/foo/hoon ".")
|
!> (parse-pile:(ford):fusion /sur/foo/hoon src)
|
||||||
|
::
|
||||||
|
++ test-parse-fascen ^- tang
|
||||||
|
=/ src "/% moo %mime\0a."
|
||||||
|
%+ expect-eq
|
||||||
|
!> ^- pile:fusion
|
||||||
|
:* sur=~ lib=~ raw=~
|
||||||
|
maz=[face=%moo mark=%mime]~
|
||||||
|
caz=~ bar=~
|
||||||
|
tssg+[%dbug [/sur/foo/hoon [[2 1] [2 2]]] [%cnts ~[[%.y 1]] ~]]~
|
||||||
|
==
|
||||||
|
!> (parse-pile:(ford):fusion /sur/foo/hoon src)
|
||||||
|
::
|
||||||
|
++ test-parse-fasbuc ^- tang
|
||||||
|
=/ src "/$ goo %mime %txt\0a."
|
||||||
|
%+ expect-eq
|
||||||
|
!> ^- pile:fusion
|
||||||
|
:* sur=~ lib=~ raw=~ maz=~
|
||||||
|
caz=[face=%goo from=%mime to=%txt]~
|
||||||
|
bar=~
|
||||||
|
tssg+[%dbug [/sur/foo/hoon [[2 1] [2 2]]] [%cnts ~[[%.y 1]] ~]]~
|
||||||
|
==
|
||||||
|
!> (parse-pile:(ford):fusion /sur/foo/hoon src)
|
||||||
::
|
::
|
||||||
++ test-parse-multiline-faslus ^- tang
|
++ test-parse-multiline-faslus ^- tang
|
||||||
=/ src
|
=/ src
|
||||||
"""
|
"""
|
||||||
:: :: ::
|
|
||||||
:::: /hoon/hood/app :: ::
|
|
||||||
:: :: ::
|
|
||||||
/? 310 :: zuse version
|
|
||||||
/- *sole
|
|
||||||
/+ sole :: libraries
|
|
||||||
:: XX these should really be separate apps, as
|
|
||||||
:: none of them interact with each other in
|
|
||||||
:: any fashion; however, to reduce boot-time
|
|
||||||
:: complexity and work around the current
|
|
||||||
:: non-functionality of end-to-end acknowledgments,
|
|
||||||
:: they have been bundled into :hood
|
|
||||||
::
|
::
|
||||||
:: |command handlers
|
/? 310 :: zuse version
|
||||||
|
::
|
||||||
|
/- *sole
|
||||||
|
::
|
||||||
|
/+ sole :: libraries
|
||||||
|
::
|
||||||
/+ hood-helm, hood-kiln, hood-drum, hood-write
|
/+ hood-helm, hood-kiln, hood-drum, hood-write
|
||||||
:: :: ::
|
::
|
||||||
.
|
.
|
||||||
"""
|
"""
|
||||||
%+ expect-eq
|
%+ expect-eq
|
||||||
@ -52,34 +74,21 @@
|
|||||||
[`%hood-drum %hood-drum]
|
[`%hood-drum %hood-drum]
|
||||||
[`%hood-write %hood-write]
|
[`%hood-write %hood-write]
|
||||||
==
|
==
|
||||||
raw=~ bar=~
|
raw=~ maz=~ caz=~ bar=~
|
||||||
hoon=tssg+[p:(need q:(tall:(vang & /app/hood/hoon) [17 1] "."))]~
|
tssg+[%dbug [/sur/foo/hoon [[10 1] [10 2]]] [%cnts ~[[%.y 1]] ~]]~
|
||||||
==
|
==
|
||||||
!> (parse-pile:(ford):fusion /app/hood/hoon src)
|
!> (parse-pile:(ford):fusion /sur/foo/hoon src)
|
||||||
::
|
::
|
||||||
++ test-cycle ^- tang
|
++ test-cycle ^- tang
|
||||||
=/ source=@t
|
=/ source=@t '/+ self\0a.'
|
||||||
'''
|
|
||||||
/+ self
|
|
||||||
.
|
|
||||||
'''
|
|
||||||
=/ =ankh:clay
|
|
||||||
:- fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %lib fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %self fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %hoon fil=`[*lobe:clay hoon+!>(source)] dir=~
|
|
||||||
== == ==
|
|
||||||
%- expect-fail
|
%- expect-fail
|
||||||
|.
|
|.
|
||||||
=/ ford
|
=/ ford
|
||||||
%: ford:fusion
|
%: ford:fusion
|
||||||
bud
|
bud
|
||||||
ankh
|
*ankh:clay
|
||||||
deletes=~
|
deletes=~
|
||||||
changes=~
|
changes=(my [/lib/self/hoon &+hoon+source]~)
|
||||||
file-store=~
|
file-store=~
|
||||||
*ford-cache:fusion
|
*ford-cache:fusion
|
||||||
==
|
==
|
||||||
@ -89,22 +98,122 @@
|
|||||||
%- expect-fail
|
%- expect-fail
|
||||||
|. (parse-pile:(ford):fusion /sur/foo/hoon "[")
|
|. (parse-pile:(ford):fusion /sur/foo/hoon "[")
|
||||||
::
|
::
|
||||||
++ test-hello-gen ^- tang
|
++ test-mar-mime ^- tang
|
||||||
=/ =ankh:clay
|
|
||||||
:- fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %gen fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %hello fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %hoon fil=`[*lobe:clay hoon+!>(hello-gen)] dir=~
|
|
||||||
== == ==
|
|
||||||
=/ ford
|
=/ ford
|
||||||
%: ford:fusion
|
%: ford:fusion
|
||||||
bud
|
bud
|
||||||
ankh
|
*ankh:clay
|
||||||
deletes=~
|
deletes=~
|
||||||
changes=(my [/gen/hello/hoon &+hoon+hello-gen]~)
|
changes=(my [/mar/mime/hoon &+hoon+mar-mime]~)
|
||||||
|
file-store=~
|
||||||
|
*ford-cache:fusion
|
||||||
|
==
|
||||||
|
=/ [res=vase nub=state:ford:fusion] (build-nave:ford %mime)
|
||||||
|
;: weld
|
||||||
|
%+ expect-eq
|
||||||
|
!>(*mime)
|
||||||
|
(slap res limb/%bunt)
|
||||||
|
::
|
||||||
|
%+ expect-eq
|
||||||
|
!> (~(gas in *(set path)) /mar/mime/hoon ~)
|
||||||
|
!> dez:(~(got by files.cache.nub) /mar/mime/hoon)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ test-mar-udon ^- tang
|
||||||
|
=/ ford
|
||||||
|
%: ford:fusion
|
||||||
|
bud
|
||||||
|
*ankh:clay
|
||||||
|
deletes=~
|
||||||
|
^= changes
|
||||||
|
%- my
|
||||||
|
:~ [/mar/udon/hoon &+hoon+mar-udon]
|
||||||
|
[/lib/cram/hoon &+hoon+lib-cram]
|
||||||
|
[/mar/txt/hoon &+hoon+mar-txt]
|
||||||
|
[/mar/txt-diff/hoon &+hoon+mar-txt-diff]
|
||||||
|
==
|
||||||
|
file-store=~
|
||||||
|
*ford-cache:fusion
|
||||||
|
==
|
||||||
|
=/ [res=vase nub=state:ford:fusion] (build-nave:ford %udon)
|
||||||
|
;: weld
|
||||||
|
%+ expect-eq
|
||||||
|
!>(*@t)
|
||||||
|
(slap res limb/%bunt)
|
||||||
|
::
|
||||||
|
%+ expect-eq
|
||||||
|
!> (~(gas in *(set path)) /mar/udon/hoon /lib/cram/hoon ~)
|
||||||
|
!> dez:(~(got by files.cache.nub) /mar/udon/hoon)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ test-cast-html-mime ^- tang
|
||||||
|
=/ changes
|
||||||
|
%- my
|
||||||
|
:~ [/mar/mime/hoon &+hoon+mar-mime]
|
||||||
|
[/mar/html/hoon &+hoon+mar-html]
|
||||||
|
==
|
||||||
|
=/ ford
|
||||||
|
%: ford:fusion
|
||||||
|
bud
|
||||||
|
*ankh:clay
|
||||||
|
deletes=~
|
||||||
|
changes
|
||||||
|
file-store=~
|
||||||
|
*ford-cache:fusion
|
||||||
|
==
|
||||||
|
=/ [res=vase nub=state:ford:fusion] (build-cast:ford %html %mime)
|
||||||
|
%+ expect-eq
|
||||||
|
(slam res !>('<html></html>'))
|
||||||
|
!> `mime`[/text/html 13 '<html></html>']
|
||||||
|
::
|
||||||
|
++ test-fascen ^- tang
|
||||||
|
=/ changes
|
||||||
|
%- my
|
||||||
|
:~ [/mar/mime/hoon &+hoon+mar-mime]
|
||||||
|
[/lib/foo/hoon &+hoon+'/% moo %mime\0abunt:moo']
|
||||||
|
==
|
||||||
|
=/ ford
|
||||||
|
%: ford:fusion
|
||||||
|
bud
|
||||||
|
*ankh:clay
|
||||||
|
deletes=~
|
||||||
|
changes
|
||||||
|
file-store=~
|
||||||
|
*ford-cache:fusion
|
||||||
|
==
|
||||||
|
=/ [res=vase nub=state:ford:fusion] (build-file:ford /lib/foo/hoon)
|
||||||
|
%+ expect-eq
|
||||||
|
res
|
||||||
|
!> *mime
|
||||||
|
::
|
||||||
|
++ test-fasbuc ^- tang
|
||||||
|
=/ changes
|
||||||
|
%- my
|
||||||
|
:~ [/mar/mime/hoon &+hoon+mar-mime]
|
||||||
|
[/mar/html/hoon &+hoon+mar-html]
|
||||||
|
[/lib/foo/hoon &+hoon+'/$ foo %mime %html\0a*foo']
|
||||||
|
==
|
||||||
|
=/ ford
|
||||||
|
%: ford:fusion
|
||||||
|
bud
|
||||||
|
*ankh:clay
|
||||||
|
deletes=~
|
||||||
|
changes
|
||||||
|
file-store=~
|
||||||
|
*ford-cache:fusion
|
||||||
|
==
|
||||||
|
=/ [res=vase nub=state:ford:fusion] (build-file:ford /lib/foo/hoon)
|
||||||
|
%+ expect-eq
|
||||||
|
res
|
||||||
|
!> ''
|
||||||
|
::
|
||||||
|
++ test-gen-hello ^- tang
|
||||||
|
=/ ford
|
||||||
|
%: ford:fusion
|
||||||
|
bud
|
||||||
|
*ankh:clay
|
||||||
|
deletes=~
|
||||||
|
changes=(my [/gen/hello/hoon &+hoon+gen-hello]~)
|
||||||
file-store=~
|
file-store=~
|
||||||
*ford-cache:fusion
|
*ford-cache:fusion
|
||||||
==
|
==
|
||||||
@ -116,37 +225,21 @@
|
|||||||
::
|
::
|
||||||
%+ expect-eq
|
%+ expect-eq
|
||||||
!> (~(gas in *(set path)) /gen/hello/hoon ~)
|
!> (~(gas in *(set path)) /gen/hello/hoon ~)
|
||||||
!> dez:(~(got by vases.cache.nub) /gen/hello/hoon)
|
!> dez:(~(got by files.cache.nub) /gen/hello/hoon)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ test-strandio-lib ^- tang
|
++ test-lib-strandio ^- tang
|
||||||
=/ =ankh:clay
|
|
||||||
:- fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %lib fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %strandio fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %hoon fil=`[*lobe:clay hoon+!>(strandio-lib)] dir=~
|
|
||||||
==
|
|
||||||
::
|
|
||||||
:+ %strand fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %hoon fil=`[*lobe:clay hoon+!>(strand-lib)] dir=~
|
|
||||||
== ==
|
|
||||||
::
|
|
||||||
:+ %sur fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %spider fil=~
|
|
||||||
%- ~(gas by *(map @tas ankh:clay))
|
|
||||||
:~ :+ %hoon fil=`[*lobe:clay hoon+!>(spider-sur)] dir=~
|
|
||||||
== == ==
|
|
||||||
=/ ford
|
=/ ford
|
||||||
%: ford:fusion
|
%: ford:fusion
|
||||||
bud
|
bud
|
||||||
ankh
|
*ankh:clay
|
||||||
deletes=~
|
deletes=~
|
||||||
changes=~
|
^= changes
|
||||||
|
%- my
|
||||||
|
:~ [/lib/strand/hoon &+hoon+lib-strand]
|
||||||
|
[/lib/strandio/hoon &+hoon+lib-strandio]
|
||||||
|
[/sur/spider/hoon &+hoon+sur-spider]
|
||||||
|
==
|
||||||
file-store=~
|
file-store=~
|
||||||
*ford-cache:fusion
|
*ford-cache:fusion
|
||||||
==
|
==
|
||||||
@ -161,7 +254,7 @@
|
|||||||
/lib/strand/hoon
|
/lib/strand/hoon
|
||||||
/sur/spider/hoon
|
/sur/spider/hoon
|
||||||
==
|
==
|
||||||
!> dez:(~(got by vases.cache.nub) /lib/strandio/hoon)
|
!> dez:(~(got by files.cache.nub) /lib/strandio/hoon)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
:: |utilities: helper functions for testing
|
:: |utilities: helper functions for testing
|
||||||
|
@ -2360,7 +2360,6 @@
|
|||||||
++ mash !!
|
++ mash !!
|
||||||
++ pact !!
|
++ pact !!
|
||||||
++ vale |=(=noun !>(;;(json noun)))
|
++ vale |=(=noun !>(;;(json noun)))
|
||||||
++ volt !!
|
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
?> =(%j view)
|
?> =(%j view)
|
||||||
|
@ -170,6 +170,10 @@
|
|||||||
%+ expect-eq
|
%+ expect-eq
|
||||||
!> [%o (molt props)]
|
!> [%o (molt props)]
|
||||||
!> (pairs props)
|
!> (pairs props)
|
||||||
|
:: sect - stored as integer number of seconds since the unix epoch
|
||||||
|
%+ expect-eq
|
||||||
|
!> [%n '1']
|
||||||
|
!> (sect ~1970.1.1..0.0.1)
|
||||||
:: time - stored as integer number of milliseconds since the unix epoch
|
:: time - stored as integer number of milliseconds since the unix epoch
|
||||||
::
|
::
|
||||||
%+ expect-eq
|
%+ expect-eq
|
||||||
|
@ -129,6 +129,30 @@
|
|||||||
!> -.b
|
!> -.b
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
++ test-ordered-map-traverse-delete-all ^- tang
|
||||||
|
;: weld
|
||||||
|
=/ q ((ordered-map ,@ ,~) lte)
|
||||||
|
=/ o (gas:q ~ ~[1/~ 2/~ 3/~])
|
||||||
|
=/ b ((traverse:q ,~) o ~ |=([~ key=@ ~] [~ %| ~]))
|
||||||
|
%+ expect-eq
|
||||||
|
!> [~ ~]
|
||||||
|
!> b
|
||||||
|
::
|
||||||
|
=/ c
|
||||||
|
:~ [[2.127 1] ~] [[2.127 2] ~] [[2.127 3] ~]
|
||||||
|
[[2.127 7] ~] [[2.127 8] ~] [[2.127 9] ~]
|
||||||
|
==
|
||||||
|
=/ compare
|
||||||
|
|= [[aa=@ ab=@] [ba=@ bb=@]]
|
||||||
|
?:((lth aa ba) %.y ?:((gth aa ba) %.n (lte ab bb)))
|
||||||
|
=/ q ((ordered-map ,[@ @] ,~) compare)
|
||||||
|
=/ o (gas:q ~ c)
|
||||||
|
=/ b ((traverse:q ,~) o ~ |=([~ key=[@ @] ~] [~ %| ~]))
|
||||||
|
%+ expect-eq
|
||||||
|
!> [~ ~]
|
||||||
|
!> b
|
||||||
|
==
|
||||||
|
::
|
||||||
++ test-ordered-map-uni ^- tang
|
++ test-ordered-map-uni ^- tang
|
||||||
::
|
::
|
||||||
=/ a=(tree [@ud @tas]) (gas:atom-map ~ (scag 4 test-items))
|
=/ a=(tree [@ud @tas]) (gas:atom-map ~ (scag 4 test-items))
|
||||||
|
36
pkg/interface/package-lock.json
generated
36
pkg/interface/package-lock.json
generated
@ -2264,6 +2264,13 @@
|
|||||||
"url": "0.10.3",
|
"url": "0.10.3",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"xml2js": "0.4.19"
|
"xml2js": "0.4.19"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"querystring": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"babel-eslint": {
|
"babel-eslint": {
|
||||||
@ -6692,6 +6699,14 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"punycode": "1.3.2",
|
"punycode": "1.3.2",
|
||||||
"querystring": "0.2.0"
|
"querystring": "0.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"querystring": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7443,9 +7458,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"querystring": {
|
"querystring": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
|
||||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
"integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg=="
|
||||||
},
|
},
|
||||||
"querystring-es3": {
|
"querystring-es3": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
@ -9620,6 +9635,13 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"punycode": "1.3.2",
|
"punycode": "1.3.2",
|
||||||
"querystring": "0.2.0"
|
"querystring": "0.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"querystring": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url-parse": {
|
"url-parse": {
|
||||||
@ -10378,6 +10400,14 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"punycode": "1.3.2",
|
"punycode": "1.3.2",
|
||||||
"querystring": "0.2.0"
|
"querystring": "0.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"querystring": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"normalize-wheel": "1.0.1",
|
"normalize-wheel": "1.0.1",
|
||||||
"oembed-parser": "^1.4.5",
|
"oembed-parser": "^1.4.5",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
"querystring": "^0.2.0",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
"react-codemirror2": "^6.0.1",
|
"react-codemirror2": "^6.0.1",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
|
24
pkg/interface/src/logic/api/gcp.ts
Normal file
24
pkg/interface/src/logic/api/gcp.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import BaseApi from './base';
|
||||||
|
import {StoreState} from '../store/type';
|
||||||
|
import {GcpToken} from '../types/gcp-state';
|
||||||
|
|
||||||
|
|
||||||
|
export default class GcpApi extends BaseApi<StoreState> {
|
||||||
|
isConfigured() {
|
||||||
|
return this.spider('noun', 'json', 'gcp-is-configured', {})
|
||||||
|
.then((data) => {
|
||||||
|
this.store.handleEvent({
|
||||||
|
data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getToken() {
|
||||||
|
return this.spider('noun', 'gcp-token', 'gcp-get-token', {})
|
||||||
|
.then((token) => {
|
||||||
|
this.store.handleEvent({
|
||||||
|
data: token
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -10,6 +10,7 @@ import GroupsApi from './groups';
|
|||||||
import LaunchApi from './launch';
|
import LaunchApi from './launch';
|
||||||
import GraphApi from './graph';
|
import GraphApi from './graph';
|
||||||
import S3Api from './s3';
|
import S3Api from './s3';
|
||||||
|
import GcpApi from './gcp';
|
||||||
import { HarkApi } from './hark';
|
import { HarkApi } from './hark';
|
||||||
import SettingsApi from './settings';
|
import SettingsApi from './settings';
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ export default class GlobalApi extends BaseApi<StoreState> {
|
|||||||
contacts = new ContactsApi(this.ship, this.channel, this.store);
|
contacts = new ContactsApi(this.ship, this.channel, this.store);
|
||||||
groups = new GroupsApi(this.ship, this.channel, this.store);
|
groups = new GroupsApi(this.ship, this.channel, this.store);
|
||||||
launch = new LaunchApi(this.ship, this.channel, this.store);
|
launch = new LaunchApi(this.ship, this.channel, this.store);
|
||||||
|
gcp = new GcpApi(this.ship, this.channel, this.store);
|
||||||
s3 = new S3Api(this.ship, this.channel, this.store);
|
s3 = new S3Api(this.ship, this.channel, this.store);
|
||||||
graph = new GraphApi(this.ship, this.channel, this.store);
|
graph = new GraphApi(this.ship, this.channel, this.store);
|
||||||
hark = new HarkApi(this.ship, this.channel, this.store);
|
hark = new HarkApi(this.ship, this.channel, this.store);
|
||||||
|
67
pkg/interface/src/logic/lib/GcpClient.ts
Normal file
67
pkg/interface/src/logic/lib/GcpClient.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Very simple GCP Storage client.
|
||||||
|
//
|
||||||
|
// It's designed to match a subset of the S3 client upload API. The upload
|
||||||
|
// function on S3 returns a ManagedUpload, which has a promise() method on
|
||||||
|
// it. We don't care about any of the other methods on ManagedUpload, so we
|
||||||
|
// just do the work in its promise() method.
|
||||||
|
//
|
||||||
|
import querystring from 'querystring';
|
||||||
|
import {
|
||||||
|
StorageAcl,
|
||||||
|
StorageClient,
|
||||||
|
StorageUpload,
|
||||||
|
UploadParams,
|
||||||
|
UploadResult
|
||||||
|
} from './StorageClient';
|
||||||
|
|
||||||
|
|
||||||
|
const ENDPOINT = 'storage.googleapis.com';
|
||||||
|
|
||||||
|
class GcpUpload implements StorageUpload {
|
||||||
|
#params: UploadParams;
|
||||||
|
#accessKey: string;
|
||||||
|
|
||||||
|
constructor(params: UploadParams, accessKey: string) {
|
||||||
|
this.#params = params;
|
||||||
|
this.#accessKey = accessKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
async promise(): UploadResult {
|
||||||
|
const {Bucket, Key, ContentType, Body} = this.#params;
|
||||||
|
const urlParams = {
|
||||||
|
uploadType: 'media',
|
||||||
|
name: Key,
|
||||||
|
predefinedAcl: 'publicRead'
|
||||||
|
};
|
||||||
|
const url = `https://${ENDPOINT}/upload/storage/v1/b/${Bucket}/o?` +
|
||||||
|
querystring.stringify(urlParams);
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append('Authorization', `Bearer ${this.#accessKey}`);
|
||||||
|
headers.append('Content-Type', ContentType);
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'cors',
|
||||||
|
cache: 'default',
|
||||||
|
headers,
|
||||||
|
referrerPolicy: 'no-referrer',
|
||||||
|
body: Body
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error('GcpClient server error', await response.json());
|
||||||
|
throw new Error(`GcpClient: response ${response.status}`);
|
||||||
|
}
|
||||||
|
return {Location: `https://${ENDPOINT}/${Bucket}/${Key}`};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GcpClient implements StorageClient {
|
||||||
|
#accessKey: string;
|
||||||
|
|
||||||
|
constructor(accessKey: string) {
|
||||||
|
this.#accessKey = accessKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
upload(params: UploadParams): StorageUpload {
|
||||||
|
return new GcpUpload(params, this.#accessKey);
|
||||||
|
}
|
||||||
|
}
|
32
pkg/interface/src/logic/lib/StorageClient.ts
Normal file
32
pkg/interface/src/logic/lib/StorageClient.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Defines a StorageClient interface interoperable between S3 and GCP Storage.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// XX kind of gross. S3 needs 'public-read', GCP needs 'publicRead'.
|
||||||
|
// Rather than write a wrapper around S3, we offer this field here, which
|
||||||
|
// should always be passed, and will be replaced by 'publicRead' in the
|
||||||
|
// GCP client.
|
||||||
|
export enum StorageAcl {
|
||||||
|
PublicRead = 'public-read'
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface UploadParams {
|
||||||
|
Bucket: string; // the bucket to upload the object to
|
||||||
|
Key: string; // the desired location within the bucket
|
||||||
|
ContentType: string; // the object's mime-type
|
||||||
|
ACL: StorageAcl; // ACL, always 'public-read'
|
||||||
|
Body: File; // the object itself
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface UploadResult {
|
||||||
|
Location: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extra layer of indirection used by S3 client.
|
||||||
|
export interface StorageUpload {
|
||||||
|
promise(): Promise<UploadResult>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface StorageClient {
|
||||||
|
upload(params: UploadParams): StorageUpload;
|
||||||
|
};
|
142
pkg/interface/src/logic/lib/gcpManager.ts
Normal file
142
pkg/interface/src/logic/lib/gcpManager.ts
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// Singleton that manages GCP token state.
|
||||||
|
//
|
||||||
|
// To use:
|
||||||
|
//
|
||||||
|
// 1. call configure with a GlobalApi and GlobalStore.
|
||||||
|
// 2. call start() to start the token refresh loop.
|
||||||
|
//
|
||||||
|
// If the ship does not have GCP storage configured, we don't try to get
|
||||||
|
// a token, but we keep checking at regular intervals to see if it gets
|
||||||
|
// configured. If GCP storage is configured, we try to invoke the GCP
|
||||||
|
// get-token thread on the ship until it gives us an access token. Once
|
||||||
|
// we have a token, we refresh it every hour or so according to its
|
||||||
|
// intrinsic expiry.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
import GlobalApi from '../api/global';
|
||||||
|
import GlobalStore from '../store/store';
|
||||||
|
|
||||||
|
|
||||||
|
class GcpManager {
|
||||||
|
#api: GlobalApi | null = null;
|
||||||
|
#store: GlobalStore | null = null;
|
||||||
|
|
||||||
|
configure(api: GlobalApi, store: GlobalStore) {
|
||||||
|
this.#api = api;
|
||||||
|
this.#store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
#running = false;
|
||||||
|
#timeoutId: number | null = null;
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (this.#running) {
|
||||||
|
console.warn('GcpManager already running');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.#api || !this.#store) {
|
||||||
|
console.error('GcpManager must have api and store set');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#running = true;
|
||||||
|
this.refreshLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if (!this.#running) {
|
||||||
|
console.warn('GcpManager already stopped');
|
||||||
|
console.assert(this.#timeoutId === null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#running = false;
|
||||||
|
if (this.#timeoutId !== null) {
|
||||||
|
clearTimeout(this.#timeoutId);
|
||||||
|
this.#timeoutId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restart() {
|
||||||
|
if (this.#running) {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
#consecutiveFailures: number = 0;
|
||||||
|
|
||||||
|
private isConfigured() {
|
||||||
|
return this.#store.state.storage.gcp.configured;
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshLoop() {
|
||||||
|
if (!this.isConfigured()) {
|
||||||
|
this.#api.gcp.isConfigured()
|
||||||
|
.then(() => {
|
||||||
|
if (this.isConfigured() === undefined) {
|
||||||
|
throw new Error("can't check whether GCP is configured?");
|
||||||
|
}
|
||||||
|
if (this.isConfigured()) {
|
||||||
|
this.refreshLoop();
|
||||||
|
} else {
|
||||||
|
this.refreshAfter(10_000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
console.error('GcpManager failure; stopping.', reason);
|
||||||
|
this.stop();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#api.gcp.getToken()
|
||||||
|
.then(() => {
|
||||||
|
const token = this.#store.state.storage.gcp?.token;
|
||||||
|
if (token) {
|
||||||
|
this.#consecutiveFailures = 0;
|
||||||
|
const interval = this.refreshInterval(token.expiresIn);
|
||||||
|
console.log('GcpManager got token; refreshing after', interval);
|
||||||
|
this.refreshAfter(interval);
|
||||||
|
} else {
|
||||||
|
throw new Error('thread succeeded, but returned no token?');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
this.#consecutiveFailures++;
|
||||||
|
console.warn('GcpManager token refresh failed; retrying with backoff');
|
||||||
|
this.refreshAfter(this.backoffInterval());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshAfter(durationMs) {
|
||||||
|
if (!this.#running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.#timeoutId !== null) {
|
||||||
|
console.warn('GcpManager already has a timeout set');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#timeoutId = setTimeout(() => {
|
||||||
|
this.#timeoutId = null;
|
||||||
|
this.refreshLoop();
|
||||||
|
}, durationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshInterval(expiresIn: number) {
|
||||||
|
// Give ourselves a minute for processing delays, but never refresh sooner
|
||||||
|
// than 30 minutes from now. (The expiry window should be about an hour.)
|
||||||
|
return Math.max(30 * 60_000, expiresIn - 60_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private backoffInterval() {
|
||||||
|
// exponential backoff.
|
||||||
|
const slotMs = 5_000;
|
||||||
|
const maxSlot = 60; // 5 minutes
|
||||||
|
const backoffSlots =
|
||||||
|
Math.floor(Math.random() * Math.min(maxSlot, this.#consecutiveFailures));
|
||||||
|
return slotMs * backoffSlots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = new GcpManager();
|
||||||
|
Object.freeze(instance);
|
||||||
|
|
||||||
|
export default instance;
|
@ -1,41 +0,0 @@
|
|||||||
import S3 from 'aws-sdk/clients/s3';
|
|
||||||
|
|
||||||
export default class S3Client {
|
|
||||||
constructor() {
|
|
||||||
this.s3 = null;
|
|
||||||
|
|
||||||
this.endpoint = '';
|
|
||||||
this.accessKeyId = '';
|
|
||||||
this.secretAccesskey = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
setCredentials(endpoint, accessKeyId, secretAccessKey) {
|
|
||||||
this.endpoint = endpoint;
|
|
||||||
this.accessKeyId = accessKeyId;
|
|
||||||
this.secretAccessKey = secretAccessKey;
|
|
||||||
|
|
||||||
this.s3 = new S3({
|
|
||||||
endpoint: endpoint,
|
|
||||||
credentials: {
|
|
||||||
accessKeyId: this.accessKeyId,
|
|
||||||
secretAccessKey: this.secretAccessKey
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async upload(bucket, filename, buffer) {
|
|
||||||
const params = {
|
|
||||||
Bucket: bucket,
|
|
||||||
Key: filename,
|
|
||||||
Body: buffer,
|
|
||||||
ACL: 'public-read',
|
|
||||||
ContentType: buffer.type
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!this.s3) {
|
|
||||||
throw new Error('S3 not initialized');
|
|
||||||
}
|
|
||||||
return this.s3.upload(params).promise();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
|||||||
import { useCallback, useMemo, useEffect, useRef, useState } from 'react';
|
import { useCallback, useMemo, useEffect, useRef, useState } from 'react';
|
||||||
import { S3State } from '../../types/s3-update';
|
import {
|
||||||
|
GcpState,
|
||||||
|
S3State,
|
||||||
|
StorageState
|
||||||
|
} from '../../types';
|
||||||
import S3 from 'aws-sdk/clients/s3';
|
import S3 from 'aws-sdk/clients/s3';
|
||||||
|
import GcpClient from './GcpClient';
|
||||||
|
import { StorageClient, StorageAcl } from './StorageClient';
|
||||||
import { dateToDa, deSig } from './util';
|
import { dateToDa, deSig } from './util';
|
||||||
|
|
||||||
export interface IuseS3 {
|
|
||||||
|
export interface IuseStorage {
|
||||||
canUpload: boolean;
|
canUpload: boolean;
|
||||||
upload: (file: File, bucket: string) => Promise<string>;
|
upload: (file: File, bucket: string) => Promise<string>;
|
||||||
uploadDefault: (file: File) => Promise<string>;
|
uploadDefault: (file: File) => Promise<string>;
|
||||||
@ -11,31 +18,43 @@ export interface IuseS3 {
|
|||||||
promptUpload: () => Promise<string | undefined>;
|
promptUpload: () => Promise<string | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useS3 = (s3: S3State, { accept = '*' } = { accept: '*' }): IuseS3 => {
|
const useStorage = ({gcp, s3}: StorageState,
|
||||||
|
{ accept = '*' } = { accept: '*' }): IuseStorage => {
|
||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
|
|
||||||
const client = useRef<S3 | null>(null);
|
const client = useRef<StorageClient | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!s3.credentials) {
|
// prefer GCP if available, else use S3.
|
||||||
|
if (gcp.token !== undefined) {
|
||||||
|
client.current = new GcpClient(gcp.token.accessKey);
|
||||||
|
} else {
|
||||||
|
// XX ships currently always have S3 credentials, but the fields are all
|
||||||
|
// set to '' if they are not configured.
|
||||||
|
if (!s3.credentials ||
|
||||||
|
!s3.credentials.accessKeyId ||
|
||||||
|
!s3.credentials.secretAccessKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
client.current = new S3({
|
client.current = new S3({
|
||||||
credentials: s3.credentials,
|
credentials: s3.credentials,
|
||||||
endpoint: s3.credentials.endpoint
|
endpoint: s3.credentials.endpoint
|
||||||
});
|
});
|
||||||
}, [s3.credentials]);
|
}
|
||||||
|
}, [gcp.token, s3.credentials]);
|
||||||
|
|
||||||
const canUpload = useMemo(
|
const canUpload = useMemo(
|
||||||
() =>
|
() =>
|
||||||
(client && s3.credentials && s3.configuration.currentBucket !== '') || false,
|
((gcp.token || (s3.credentials && s3.credentials.accessKeyId &&
|
||||||
[s3.credentials, s3.configuration.currentBucket, client]
|
s3.credentials.secretAccessKey)) &&
|
||||||
|
s3.configuration.currentBucket !== '') || false,
|
||||||
|
[s3.credentials, gcp.token, s3.configuration.currentBucket]
|
||||||
);
|
);
|
||||||
|
|
||||||
const upload = useCallback(
|
const upload = useCallback(
|
||||||
async (file: File, bucket: string) => {
|
async (file: File, bucket: string) => {
|
||||||
if (!client.current) {
|
if (client.current === null) {
|
||||||
throw new Error('S3 not ready');
|
throw new Error('Storage not ready');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileParts = file.name.split('.');
|
const fileParts = file.name.split('.');
|
||||||
@ -47,7 +66,7 @@ const useS3 = (s3: S3State, { accept = '*' } = { accept: '*' }): IuseS3 => {
|
|||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
Key: `${window.ship}/${timestamp}-${fileName}.${fileExtension}`,
|
Key: `${window.ship}/${timestamp}-${fileName}.${fileExtension}`,
|
||||||
Body: file,
|
Body: file,
|
||||||
ACL: 'public-read',
|
ACL: StorageAcl.PublicRead,
|
||||||
ContentType: file.type
|
ContentType: file.type
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +86,7 @@ const useS3 = (s3: S3State, { accept = '*' } = { accept: '*' }): IuseS3 => {
|
|||||||
throw new Error('current bucket not set');
|
throw new Error('current bucket not set');
|
||||||
}
|
}
|
||||||
return upload(file, s3.configuration.currentBucket);
|
return upload(file, s3.configuration.currentBucket);
|
||||||
}, [s3]);
|
}, [s3, upload]);
|
||||||
|
|
||||||
const promptUpload = useCallback(
|
const promptUpload = useCallback(
|
||||||
() => {
|
() => {
|
||||||
@ -92,7 +111,7 @@ const useS3 = (s3: S3State, { accept = '*' } = { accept: '*' }): IuseS3 => {
|
|||||||
[uploadDefault]
|
[uploadDefault]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { canUpload, upload, uploadDefault, uploading, promptUpload };
|
return {canUpload, upload, uploadDefault, uploading, promptUpload};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useS3;
|
export default useStorage;
|
37
pkg/interface/src/logic/reducers/gcp-reducer.ts
Normal file
37
pkg/interface/src/logic/reducers/gcp-reducer.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import {StoreState} from '../store/type';
|
||||||
|
import {GcpToken} from '../../types/gcp-state';
|
||||||
|
|
||||||
|
type GcpState = Pick<StoreState, 'gcp'>;
|
||||||
|
|
||||||
|
export default class GcpReducer<S extends GcpState>{
|
||||||
|
reduce(json: Cage, state: S) {
|
||||||
|
this.reduceConfigured(json, state);
|
||||||
|
this.reduceToken(json, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
reduceConfigured(json, state) {
|
||||||
|
let data = json['gcp-configured'];
|
||||||
|
if (data !== undefined) {
|
||||||
|
state.storage.gcp.configured = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reduceToken(json: Cage, state: S) {
|
||||||
|
let data = json['gcp-token'];
|
||||||
|
if (data) {
|
||||||
|
this.setToken(data, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setToken(data: any, state: S) {
|
||||||
|
if (this.isToken(data)) {
|
||||||
|
state.storage.gcp.token = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isToken(token: any): token is GcpToken {
|
||||||
|
return (typeof(token.accessKey) === 'string' &&
|
||||||
|
typeof(token.expiresIn) === 'number');
|
||||||
|
}
|
||||||
|
}
|
@ -23,14 +23,14 @@ export default class S3Reducer<S extends S3State> {
|
|||||||
credentials(json: S3Update, state: S) {
|
credentials(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'credentials', false);
|
const data = _.get(json, 'credentials', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
state.s3.credentials = data;
|
state.storage.s3.credentials = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration(json: S3Update, state: S) {
|
configuration(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'configuration', false);
|
const data = _.get(json, 'configuration', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
state.s3.configuration = {
|
state.storage.s3.configuration = {
|
||||||
buckets: new Set(data.buckets),
|
buckets: new Set(data.buckets),
|
||||||
currentBucket: data.currentBucket
|
currentBucket: data.currentBucket
|
||||||
};
|
};
|
||||||
@ -39,44 +39,44 @@ export default class S3Reducer<S extends S3State> {
|
|||||||
|
|
||||||
currentBucket(json: S3Update, state: S) {
|
currentBucket(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'setCurrentBucket', false);
|
const data = _.get(json, 'setCurrentBucket', false);
|
||||||
if (data && state.s3) {
|
if (data && state.storage.s3) {
|
||||||
state.s3.configuration.currentBucket = data;
|
state.storage.s3.configuration.currentBucket = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addBucket(json: S3Update, state: S) {
|
addBucket(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'addBucket', false);
|
const data = _.get(json, 'addBucket', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
state.s3.configuration.buckets =
|
state.storage.s3.configuration.buckets =
|
||||||
state.s3.configuration.buckets.add(data);
|
state.storage.s3.configuration.buckets.add(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeBucket(json: S3Update, state: S) {
|
removeBucket(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'removeBucket', false);
|
const data = _.get(json, 'removeBucket', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
state.s3.configuration.buckets.delete(data);
|
state.storage.s3.configuration.buckets.delete(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint(json: S3Update, state: S) {
|
endpoint(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'setEndpoint', false);
|
const data = _.get(json, 'setEndpoint', false);
|
||||||
if (data && state.s3.credentials) {
|
if (data && state.storage.s3.credentials) {
|
||||||
state.s3.credentials.endpoint = data;
|
state.storage.s3.credentials.endpoint = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKeyId(json: S3Update , state: S) {
|
accessKeyId(json: S3Update , state: S) {
|
||||||
const data = _.get(json, 'setAccessKeyId', false);
|
const data = _.get(json, 'setAccessKeyId', false);
|
||||||
if (data && state.s3.credentials) {
|
if (data && state.storage.s3.credentials) {
|
||||||
state.s3.credentials.accessKeyId = data;
|
state.storage.s3.credentials.accessKeyId = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
secretAccessKey(json: S3Update, state: S) {
|
secretAccessKey(json: S3Update, state: S) {
|
||||||
const data = _.get(json, 'setSecretAccessKey', false);
|
const data = _.get(json, 'setSecretAccessKey', false);
|
||||||
if (data && state.s3.credentials) {
|
if (data && state.storage.s3.credentials) {
|
||||||
state.s3.credentials.secretAccessKey = data;
|
state.storage.s3.credentials.secretAccessKey = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import GroupReducer from '../reducers/group-update';
|
|||||||
import LaunchReducer from '../reducers/launch-update';
|
import LaunchReducer from '../reducers/launch-update';
|
||||||
import ConnectionReducer from '../reducers/connection';
|
import ConnectionReducer from '../reducers/connection';
|
||||||
import SettingsReducer from '../reducers/settings-update';
|
import SettingsReducer from '../reducers/settings-update';
|
||||||
|
import GcpReducer from '../reducers/gcp-reducer';
|
||||||
import { OrderedMap } from '../lib/OrderedMap';
|
import { OrderedMap } from '../lib/OrderedMap';
|
||||||
import { BigIntOrderedMap } from '../lib/BigIntOrderedMap';
|
import { BigIntOrderedMap } from '../lib/BigIntOrderedMap';
|
||||||
import { GroupViewReducer } from '../reducers/group-view';
|
import { GroupViewReducer } from '../reducers/group-view';
|
||||||
@ -29,6 +30,7 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
launchReducer = new LaunchReducer();
|
launchReducer = new LaunchReducer();
|
||||||
connReducer = new ConnectionReducer();
|
connReducer = new ConnectionReducer();
|
||||||
settingsReducer = new SettingsReducer();
|
settingsReducer = new SettingsReducer();
|
||||||
|
gcpReducer = new GcpReducer();
|
||||||
|
|
||||||
pastActions: Record<string, any> = {}
|
pastActions: Record<string, any> = {}
|
||||||
|
|
||||||
@ -70,6 +72,8 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
},
|
},
|
||||||
weather: {},
|
weather: {},
|
||||||
userLocation: null,
|
userLocation: null,
|
||||||
|
storage: {
|
||||||
|
gcp: {},
|
||||||
s3: {
|
s3: {
|
||||||
configuration: {
|
configuration: {
|
||||||
buckets: new Set(),
|
buckets: new Set(),
|
||||||
@ -77,6 +81,7 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
},
|
},
|
||||||
credentials: null
|
credentials: null
|
||||||
},
|
},
|
||||||
|
},
|
||||||
isContactPublic: false,
|
isContactPublic: false,
|
||||||
contacts: {},
|
contacts: {},
|
||||||
nackedContacts: new Set(),
|
nackedContacts: new Set(),
|
||||||
@ -116,6 +121,7 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
HarkReducer(data, this.state);
|
HarkReducer(data, this.state);
|
||||||
ContactReducer(data, this.state);
|
ContactReducer(data, this.state);
|
||||||
this.settingsReducer.reduce(data);
|
this.settingsReducer.reduce(data);
|
||||||
|
this.gcpReducer.reduce(data, this.state);
|
||||||
GroupViewReducer(data, this.state);
|
GroupViewReducer(data, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { Invites } from '@urbit/api/invite';
|
|||||||
import { Associations } from '@urbit/api/metadata';
|
import { Associations } from '@urbit/api/metadata';
|
||||||
import { Rolodex } from '@urbit/api/contacts';
|
import { Rolodex } from '@urbit/api/contacts';
|
||||||
import { Groups } from '@urbit/api/groups';
|
import { Groups } from '@urbit/api/groups';
|
||||||
import { S3State } from '~/types/s3-update';
|
import { StorageState } from '~/types/storage-state';
|
||||||
import { LaunchState, WeatherState } from '~/types/launch-update';
|
import { LaunchState, WeatherState } from '~/types/launch-update';
|
||||||
import { ConnectionStatus } from '~/types/connection';
|
import { ConnectionStatus } from '~/types/connection';
|
||||||
import { Graphs } from '@urbit/api/graph';
|
import { Graphs } from '@urbit/api/graph';
|
||||||
@ -31,7 +31,7 @@ export interface StoreState {
|
|||||||
groups: Groups;
|
groups: Groups;
|
||||||
groupKeys: Set<Path>;
|
groupKeys: Set<Path>;
|
||||||
nackedContacts: Set<Patp>
|
nackedContacts: Set<Patp>
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
graphs: Graphs;
|
graphs: Graphs;
|
||||||
graphKeys: Set<string>;
|
graphKeys: Set<string>;
|
||||||
|
|
||||||
|
9
pkg/interface/src/types/gcp-state.ts
Normal file
9
pkg/interface/src/types/gcp-state.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface GcpToken {
|
||||||
|
accessKey: string;
|
||||||
|
expiresIn: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface GcpState {
|
||||||
|
configured?: boolean;
|
||||||
|
token?: GcpToken
|
||||||
|
};
|
@ -3,6 +3,8 @@ export * from './connection';
|
|||||||
export * from './global';
|
export * from './global';
|
||||||
export * from './launch-update';
|
export * from './launch-update';
|
||||||
export * from './local-update';
|
export * from './local-update';
|
||||||
|
export * from './storage-state';
|
||||||
|
export * from './gcp-state';
|
||||||
export * from './s3-update';
|
export * from './s3-update';
|
||||||
export * from './workspace';
|
export * from './workspace';
|
||||||
export * from './util';
|
export * from './util';
|
||||||
|
8
pkg/interface/src/types/storage-state.ts
Normal file
8
pkg/interface/src/types/storage-state.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import {GcpState} from './gcp-state';
|
||||||
|
import {S3State} from './s3-update';
|
||||||
|
|
||||||
|
|
||||||
|
export interface StorageState {
|
||||||
|
gcp: GcpState;
|
||||||
|
s3: S3State;
|
||||||
|
};
|
@ -27,6 +27,7 @@ import GlobalSubscription from '~/logic/subscription/global';
|
|||||||
import GlobalApi from '~/logic/api/global';
|
import GlobalApi from '~/logic/api/global';
|
||||||
import { uxToHex } from '~/logic/lib/util';
|
import { uxToHex } from '~/logic/lib/util';
|
||||||
import { foregroundFromBackground } from '~/logic/lib/sigil';
|
import { foregroundFromBackground } from '~/logic/lib/sigil';
|
||||||
|
import gcpManager from '~/logic/lib/gcpManager';
|
||||||
import { withLocalState } from '~/logic/state/local';
|
import { withLocalState } from '~/logic/state/local';
|
||||||
import { withSettingsState } from '~/logic/state/settings';
|
import { withSettingsState } from '~/logic/state/settings';
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ class App extends React.Component {
|
|||||||
|
|
||||||
this.appChannel = new window.channel();
|
this.appChannel = new window.channel();
|
||||||
this.api = new GlobalApi(this.ship, this.appChannel, this.store);
|
this.api = new GlobalApi(this.ship, this.appChannel, this.store);
|
||||||
|
gcpManager.configure(this.api, this.store);
|
||||||
this.subscription =
|
this.subscription =
|
||||||
new GlobalSubscription(this.store, this.api, this.appChannel);
|
new GlobalSubscription(this.store, this.api, this.appChannel);
|
||||||
|
|
||||||
@ -97,6 +99,7 @@ class App extends React.Component {
|
|||||||
this.api.local.getBaseHash();
|
this.api.local.getBaseHash();
|
||||||
this.api.settings.getAll();
|
this.api.settings.getAll();
|
||||||
this.store.rehydrate();
|
this.store.rehydrate();
|
||||||
|
gcpManager.start();
|
||||||
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
|
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
@ -116,8 +119,8 @@ class App extends React.Component {
|
|||||||
|
|
||||||
faviconString() {
|
faviconString() {
|
||||||
let background = '#ffffff';
|
let background = '#ffffff';
|
||||||
if (this.state.contacts.hasOwnProperty('/~/default')) {
|
if (this.state.contacts.hasOwnProperty(`~${window.ship}`)) {
|
||||||
background = `#${uxToHex(this.state.contacts['/~/default'][window.ship].color)}`;
|
background = `#${uxToHex(this.state.contacts[`~${window.ship}`].color)}`;
|
||||||
}
|
}
|
||||||
const foreground = foregroundFromBackground(background);
|
const foreground = foregroundFromBackground(background);
|
||||||
const svg = sigiljs({
|
const svg = sigiljs({
|
||||||
|
@ -13,7 +13,6 @@ import { ShareProfile } from '~/views/apps/chat/components/ShareProfile';
|
|||||||
import SubmitDragger from '~/views/components/SubmitDragger';
|
import SubmitDragger from '~/views/components/SubmitDragger';
|
||||||
import { useLocalStorageState } from '~/logic/lib/useLocalStorageState';
|
import { useLocalStorageState } from '~/logic/lib/useLocalStorageState';
|
||||||
import { Loading } from '~/views/components/Loading';
|
import { Loading } from '~/views/components/Loading';
|
||||||
import useS3 from '~/logic/lib/useS3';
|
|
||||||
import { isWriter, resourceFromPath } from '~/logic/lib/group';
|
import { isWriter, resourceFromPath } from '~/logic/lib/group';
|
||||||
|
|
||||||
import './css/custom.css';
|
import './css/custom.css';
|
||||||
@ -180,7 +179,7 @@ export function ChatResource(props: ChatResourceProps) {
|
|||||||
(!showBanner && hasLoadedAllowed) ? contacts : modifiedContacts
|
(!showBanner && hasLoadedAllowed) ? contacts : modifiedContacts
|
||||||
}
|
}
|
||||||
onUnmount={appendUnsent}
|
onUnmount={appendUnsent}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
placeholder="Message..."
|
placeholder="Message..."
|
||||||
message={unsent[station] || ''}
|
message={unsent[station] || ''}
|
||||||
deleteMessage={clearUnsent}
|
deleteMessage={clearUnsent}
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ChatEditor from './chat-editor';
|
import ChatEditor from './chat-editor';
|
||||||
import { IuseS3 } from '~/logic/lib/useS3';
|
import { IuseStorage } from '~/logic/lib/useStorage';
|
||||||
import { uxToHex } from '~/logic/lib/util';
|
import { uxToHex } from '~/logic/lib/util';
|
||||||
import { Sigil } from '~/logic/lib/sigil';
|
import { Sigil } from '~/logic/lib/sigil';
|
||||||
import { createPost } from '~/logic/api/graph';
|
import { createPost } from '~/logic/api/graph';
|
||||||
import tokenizeMessage, { isUrl } from '~/logic/lib/tokenizeMessage';
|
import tokenizeMessage, { isUrl } from '~/logic/lib/tokenizeMessage';
|
||||||
import GlobalApi from '~/logic/api/global';
|
import GlobalApi from '~/logic/api/global';
|
||||||
import { Envelope } from '~/types/chat-update';
|
import { Envelope } from '~/types/chat-update';
|
||||||
|
import { StorageState } from '~/types';
|
||||||
import { Contacts, Content } from '@urbit/api';
|
import { Contacts, Content } from '@urbit/api';
|
||||||
import { Row, BaseImage, Box, Icon, LoadingSpinner } from '@tlon/indigo-react';
|
import { Row, BaseImage, Box, Icon, LoadingSpinner } from '@tlon/indigo-react';
|
||||||
import withS3 from '~/views/components/withS3';
|
import withStorage from '~/views/components/withStorage';
|
||||||
import { withLocalState } from '~/logic/state/local';
|
import { withLocalState } from '~/logic/state/local';
|
||||||
|
|
||||||
type ChatInputProps = IuseS3 & {
|
type ChatInputProps = IuseStorage & {
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
numMsgs: number;
|
numMsgs: number;
|
||||||
station: unknown;
|
station: unknown;
|
||||||
@ -20,7 +21,7 @@ type ChatInputProps = IuseS3 & {
|
|||||||
envelopes: Envelope[];
|
envelopes: Envelope[];
|
||||||
contacts: Contacts;
|
contacts: Contacts;
|
||||||
onUnmount(msg: string): void;
|
onUnmount(msg: string): void;
|
||||||
s3: unknown;
|
storage: StorageState;
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
message: string;
|
message: string;
|
||||||
deleteMessage(): void;
|
deleteMessage(): void;
|
||||||
@ -207,4 +208,4 @@ class ChatInput extends Component<ChatInputProps, ChatInputState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withLocalState(withS3(ChatInput, { accept: 'image/*' }), ['hideAvatars']);
|
export default withLocalState(withStorage(ChatInput, { accept: 'image/*' }), ['hideAvatars']);
|
||||||
|
@ -156,7 +156,8 @@ h2 {
|
|||||||
blockquote {
|
blockquote {
|
||||||
padding: 0 0 0 16px;
|
padding: 0 0 0 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-left: 1px solid black;
|
color: inherit;
|
||||||
|
border-left: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@ -173,6 +174,7 @@ blockquote {
|
|||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
color: inherit;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,9 +310,6 @@ pre.CodeMirror-placeholder.CodeMirror-line-like {
|
|||||||
/* dark */
|
/* dark */
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
blockquote {
|
|
||||||
border-left: 1px solid inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* codemirror */
|
/* codemirror */
|
||||||
.chat .cm-s-tlon.CodeMirror {
|
.chat .cm-s-tlon.CodeMirror {
|
||||||
|
@ -33,9 +33,9 @@ export function LinkResource(props: LinkResourceProps) {
|
|||||||
associations,
|
associations,
|
||||||
graphKeys,
|
graphKeys,
|
||||||
unreads,
|
unreads,
|
||||||
s3,
|
pendingIndices,
|
||||||
history,
|
storage,
|
||||||
pendingIndices
|
history
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const rid = association.resource;
|
const rid = association.resource;
|
||||||
@ -70,7 +70,7 @@ export function LinkResource(props: LinkResourceProps) {
|
|||||||
return (
|
return (
|
||||||
<LinkWindow
|
<LinkWindow
|
||||||
key={rid}
|
key={rid}
|
||||||
s3={s3}
|
storage={storage}
|
||||||
association={resource}
|
association={resource}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
resource={resourcePath}
|
resource={resourcePath}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import React, { useRef, useCallback, useEffect, useMemo } from 'react';
|
import React, {
|
||||||
|
useRef,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
Component,
|
||||||
|
} from "react";
|
||||||
|
|
||||||
import { Col, Text } from '@tlon/indigo-react';
|
import { Col, Text } from "@tlon/indigo-react";
|
||||||
import bigInt from 'big-integer';
|
import bigInt from "big-integer";
|
||||||
import {
|
import { Association, Graph, Unreads, Group, Rolodex } from "@urbit/api";
|
||||||
Association,
|
|
||||||
Graph,
|
|
||||||
Unreads,
|
|
||||||
Group,
|
|
||||||
Rolodex,
|
|
||||||
} from '@urbit/api';
|
|
||||||
|
|
||||||
import GlobalApi from '~/logic/api/global';
|
import GlobalApi from "~/logic/api/global";
|
||||||
import VirtualScroller from '~/views/components/VirtualScroller';
|
import VirtualScroller from "~/views/components/VirtualScroller";
|
||||||
import { LinkItem } from './components/LinkItem';
|
import { LinkItem } from "./components/LinkItem";
|
||||||
import LinkSubmit from './components/LinkSubmit';
|
import LinkSubmit from "./components/LinkSubmit";
|
||||||
import { isWriter } from '~/logic/lib/group';
|
import { isWriter } from "~/logic/lib/group";
|
||||||
import { S3State } from '~/types/s3-update';
|
import { StorageState } from "~/types";
|
||||||
|
|
||||||
interface LinkWindowProps {
|
interface LinkWindowProps {
|
||||||
association: Association;
|
association: Association;
|
||||||
@ -29,39 +29,93 @@ interface LinkWindowProps {
|
|||||||
group: Group;
|
group: Group;
|
||||||
path: string;
|
path: string;
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
export function LinkWindow(props: LinkWindowProps) {
|
|
||||||
const { graph, api, association, pendingSize } = props;
|
|
||||||
const fetchLinks = useCallback(
|
|
||||||
async (newer: boolean) => {
|
|
||||||
return true;
|
|
||||||
/* stubbed, should we generalize the display of graphs in virtualscroller? */
|
|
||||||
}, []
|
|
||||||
);
|
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
height: "100%",
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
};
|
||||||
|
|
||||||
|
export class LinkWindow extends Component<LinkWindowProps, {}> {
|
||||||
|
fetchLinks = async () => true;
|
||||||
|
|
||||||
|
canWrite() {
|
||||||
|
const { group, association } = this.props;
|
||||||
|
return isWriter(group, association.resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderItem = ({ index, scrollWindow }) => {
|
||||||
|
const { props } = this;
|
||||||
|
const { association, graph, api } = props;
|
||||||
|
const [, , ship, name] = association.resource.split("/");
|
||||||
|
const node = graph.get(index);
|
||||||
const first = graph.peekLargest()?.[0];
|
const first = graph.peekLargest()?.[0];
|
||||||
const [,,ship, name] = association.resource.split('/');
|
const post = node?.post;
|
||||||
const canWrite = isWriter(props.group, association.resource);
|
if (!node || !post) {
|
||||||
|
return null;
|
||||||
const style = useMemo(() =>
|
}
|
||||||
({
|
const linkProps = {
|
||||||
height: '100%',
|
...props,
|
||||||
width: '100%',
|
node,
|
||||||
display: 'flex',
|
};
|
||||||
flexDirection: 'column',
|
if (this.canWrite() && index.eq(first ?? bigInt.zero)) {
|
||||||
alignItems: 'center'
|
return (
|
||||||
}), []);
|
<React.Fragment key={index.toString()}>
|
||||||
|
<Col
|
||||||
|
key={index.toString()}
|
||||||
|
mx="auto"
|
||||||
|
mt="4"
|
||||||
|
maxWidth="768px"
|
||||||
|
width="100%"
|
||||||
|
flexShrink={0}
|
||||||
|
px={3}
|
||||||
|
>
|
||||||
|
<LinkSubmit
|
||||||
|
storage={props.storage}
|
||||||
|
name={name}
|
||||||
|
ship={ship.slice(1)}
|
||||||
|
api={api}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<LinkItem {...linkProps} />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <LinkItem key={index.toString()} {...linkProps} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { graph, api, association, storage, pendingSize } = this.props;
|
||||||
|
const first = graph.peekLargest()?.[0];
|
||||||
|
const [, , ship, name] = association.resource.split("/");
|
||||||
if (!first) {
|
if (!first) {
|
||||||
return (
|
return (
|
||||||
<Col key={0} mx="auto" mt="4" maxWidth="768px" width="100%" flexShrink={0} px={3}>
|
<Col
|
||||||
{ canWrite ? (
|
key={0}
|
||||||
<LinkSubmit s3={props.s3} name={name} ship={ship.slice(1)} api={api} />
|
mx="auto"
|
||||||
|
mt="4"
|
||||||
|
maxWidth="768px"
|
||||||
|
width="100%"
|
||||||
|
flexShrink={0}
|
||||||
|
px={3}
|
||||||
|
>
|
||||||
|
{this.canWrite() ? (
|
||||||
|
<LinkSubmit
|
||||||
|
storage={storage}
|
||||||
|
name={name}
|
||||||
|
ship={ship.slice(1)}
|
||||||
|
api={api}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text>There are no links here yet. You do not have permission to post to this collection.</Text>
|
<Text>
|
||||||
)
|
There are no links here yet. You do not have permission to post to
|
||||||
}
|
this collection.
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -70,36 +124,16 @@ export function LinkWindow(props: LinkWindowProps) {
|
|||||||
<Col width="100%" height="100%" position="relative">
|
<Col width="100%" height="100%" position="relative">
|
||||||
<VirtualScroller
|
<VirtualScroller
|
||||||
origin="top"
|
origin="top"
|
||||||
|
offset={0}
|
||||||
style={style}
|
style={style}
|
||||||
onStartReached={() => {}}
|
|
||||||
onScroll={() => {}}
|
|
||||||
data={graph}
|
data={graph}
|
||||||
averageHeight={100}
|
averageHeight={100}
|
||||||
size={graph.size}
|
size={graph.size}
|
||||||
pendingSize={pendingSize}
|
pendingSize={pendingSize}
|
||||||
renderer={({ index, scrollWindow }) => {
|
renderer={this.renderItem}
|
||||||
const node = graph.get(index);
|
loadRows={this.fetchLinks}
|
||||||
const post = node?.post;
|
|
||||||
if (!node || !post)
|
|
||||||
return null;
|
|
||||||
const linkProps = {
|
|
||||||
...props,
|
|
||||||
node,
|
|
||||||
};
|
|
||||||
if(canWrite && index.eq(first ?? bigInt.zero)) {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={index.toString()}>
|
|
||||||
<Col key={index.toString()} mx="auto" mt="4" maxWidth="768px" width="100%" flexShrink={0} px={3}>
|
|
||||||
<LinkSubmit s3={props.s3} name={name} ship={ship.slice(1)} api={api} />
|
|
||||||
</Col>
|
|
||||||
<LinkItem {...linkProps} />
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <LinkItem key={index.toString()} {...linkProps} />;
|
|
||||||
}}
|
|
||||||
loadRows={fetchLinks}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,22 @@ import { BaseInput, Box, Button, LoadingSpinner, Text } from '@tlon/indigo-react
|
|||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import GlobalApi from '~/logic/api/global';
|
import GlobalApi from '~/logic/api/global';
|
||||||
import { useFileDrag } from '~/logic/lib/useDrag';
|
import { useFileDrag } from '~/logic/lib/useDrag';
|
||||||
import useS3 from '~/logic/lib/useS3';
|
import useStorage from '~/logic/lib/useStorage';
|
||||||
import { S3State } from '@urbit/api';
|
import { StorageState } from '~/types';
|
||||||
import SubmitDragger from '~/views/components/SubmitDragger';
|
import SubmitDragger from '~/views/components/SubmitDragger';
|
||||||
import { createPost } from '~/logic/api/graph';
|
import { createPost } from '~/logic/api/graph';
|
||||||
import { hasProvider } from 'oembed-parser';
|
import { hasProvider } from 'oembed-parser';
|
||||||
|
|
||||||
interface LinkSubmitProps {
|
interface LinkSubmitProps {
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
name: string;
|
name: string;
|
||||||
ship: string;
|
ship: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LinkSubmit = (props: LinkSubmitProps) => {
|
const LinkSubmit = (props: LinkSubmitProps) => {
|
||||||
const { canUpload, uploadDefault, uploading, promptUpload } = useS3(props.s3);
|
const { canUpload, uploadDefault, uploading, promptUpload } =
|
||||||
|
useStorage(props.storage);
|
||||||
|
|
||||||
const [submitFocused, setSubmitFocused] = useState(false);
|
const [submitFocused, setSubmitFocused] = useState(false);
|
||||||
const [urlFocused, setUrlFocused] = useState(false);
|
const [urlFocused, setUrlFocused] = useState(false);
|
||||||
|
@ -48,7 +48,7 @@ const emptyContact = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function ProfileHeaderImageEdit(props: any): ReactElement {
|
export function ProfileHeaderImageEdit(props: any): ReactElement {
|
||||||
const { contact, s3, setFieldValue, handleHideCover } = { ...props };
|
const { contact, storage, setFieldValue, handleHideCover } = { ...props };
|
||||||
const [editCover, setEditCover] = useState(false);
|
const [editCover, setEditCover] = useState(false);
|
||||||
const [removedCoverLabel, setRemovedCoverLabel] = useState('Remove Header');
|
const [removedCoverLabel, setRemovedCoverLabel] = useState('Remove Header');
|
||||||
const handleClear = (e) => {
|
const handleClear = (e) => {
|
||||||
@ -63,7 +63,7 @@ export function ProfileHeaderImageEdit(props: any): ReactElement {
|
|||||||
{contact?.cover ? (
|
{contact?.cover ? (
|
||||||
<div>
|
<div>
|
||||||
{editCover ? (
|
{editCover ? (
|
||||||
<ImageInput id='cover' s3={s3} marginTop='-8px' />
|
<ImageInput id='cover' storage={storage} marginTop='-8px' />
|
||||||
) : (
|
) : (
|
||||||
<Row>
|
<Row>
|
||||||
<Button mr='2' onClick={() => setEditCover(true)}>
|
<Button mr='2' onClick={() => setEditCover(true)}>
|
||||||
@ -76,14 +76,14 @@ export function ProfileHeaderImageEdit(props: any): ReactElement {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ImageInput id='cover' s3={s3} marginTop='-8px' />
|
<ImageInput id='cover' storage={storage} marginTop='-8px' />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EditProfile(props: any): ReactElement {
|
export function EditProfile(props: any): ReactElement {
|
||||||
const { contact, ship, api, isPublic } = props;
|
const { contact, storage, ship, api, isPublic } = props;
|
||||||
const [hideCover, setHideCover] = useState(false);
|
const [hideCover, setHideCover] = useState(false);
|
||||||
|
|
||||||
const handleHideCover = (value) => {
|
const handleHideCover = (value) => {
|
||||||
@ -179,7 +179,7 @@ export function EditProfile(props: any): ReactElement {
|
|||||||
<ProfileImages hideCover={hideCover} contact={contact} ship={ship}>
|
<ProfileImages hideCover={hideCover} contact={contact} ship={ship}>
|
||||||
<ProfileHeaderImageEdit
|
<ProfileHeaderImageEdit
|
||||||
contact={contact}
|
contact={contact}
|
||||||
s3={props.s3}
|
storage={storage}
|
||||||
setFieldValue={setFieldValue}
|
setFieldValue={setFieldValue}
|
||||||
handleHideCover={handleHideCover}
|
handleHideCover={handleHideCover}
|
||||||
/>
|
/>
|
||||||
@ -193,14 +193,14 @@ export function EditProfile(props: any): ReactElement {
|
|||||||
<ImageInput
|
<ImageInput
|
||||||
id='avatar'
|
id='avatar'
|
||||||
label='Overlay Avatar (may be hidden by other users)'
|
label='Overlay Avatar (may be hidden by other users)'
|
||||||
s3={props.s3}
|
storage={storage}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Input id='nickname' label='Custom Name' mb={3} />
|
<Input id='nickname' label='Custom Name' mb={3} />
|
||||||
<Col width='100%'>
|
<Col width='100%'>
|
||||||
<Text mb={2}>Description</Text>
|
<Text mb={2}>Description</Text>
|
||||||
<MarkdownField id='bio' mb={3} s3={props.s3} />
|
<MarkdownField id='bio' mb={3} storage={storage} />
|
||||||
</Col>
|
</Col>
|
||||||
<Checkbox mb={3} id='isPublic' label='Public Profile' />
|
<Checkbox mb={3} id='isPublic' label='Public Profile' />
|
||||||
<GroupSearch
|
<GroupSearch
|
||||||
|
@ -167,11 +167,11 @@ export function Profile(props: any): ReactElement {
|
|||||||
<Center p={[0, 4]} height='100%' width='100%'>
|
<Center p={[0, 4]} height='100%' width='100%'>
|
||||||
<Box ref={anchorRef} maxWidth='600px' width='100%' position='relative'>
|
<Box ref={anchorRef} maxWidth='600px' width='100%' position='relative'>
|
||||||
<ViewProfile
|
<ViewProfile
|
||||||
api={props.api}
|
|
||||||
nacked={nacked}
|
nacked={nacked}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
contact={contact}
|
contact={contact}
|
||||||
isPublic={isPublic}
|
isPublic={isPublic}
|
||||||
|
api={props.api}
|
||||||
groups={props.groups}
|
groups={props.groups}
|
||||||
associations={props.associations}
|
associations={props.associations}
|
||||||
/>
|
/>
|
||||||
@ -187,7 +187,7 @@ export function Profile(props: any): ReactElement {
|
|||||||
<EditProfile
|
<EditProfile
|
||||||
ship={ship}
|
ship={ship}
|
||||||
contact={contact}
|
contact={contact}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
api={props.api}
|
api={props.api}
|
||||||
groups={props.groups}
|
groups={props.groups}
|
||||||
associations={props.associations}
|
associations={props.associations}
|
||||||
|
@ -46,7 +46,7 @@ export default function ProfileScreen(props: any) {
|
|||||||
groups={props.groups}
|
groups={props.groups}
|
||||||
contact={contact}
|
contact={contact}
|
||||||
api={props.api}
|
api={props.api}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
isPublic={isPublic}
|
isPublic={isPublic}
|
||||||
nackedContacts={props.nackedContacts}
|
nackedContacts={props.nackedContacts}
|
||||||
|
@ -35,7 +35,7 @@ export function PublishResource(props: PublishResourceProps) {
|
|||||||
location={props.location}
|
location={props.location}
|
||||||
unreads={props.unreads}
|
unreads={props.unreads}
|
||||||
graphs={props.graphs}
|
graphs={props.graphs}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -9,7 +9,7 @@ import { PostFormSchema, PostForm } from './NoteForm';
|
|||||||
import GlobalApi from '~/logic/api/global';
|
import GlobalApi from '~/logic/api/global';
|
||||||
import { getLatestRevision, editPost } from '~/logic/lib/publish';
|
import { getLatestRevision, editPost } from '~/logic/lib/publish';
|
||||||
import { useWaitForProps } from '~/logic/lib/useWaitForProps';
|
import { useWaitForProps } from '~/logic/lib/useWaitForProps';
|
||||||
import { S3State } from '~/types';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
interface EditPostProps {
|
interface EditPostProps {
|
||||||
ship: string;
|
ship: string;
|
||||||
@ -17,11 +17,11 @@ interface EditPostProps {
|
|||||||
note: GraphNode;
|
note: GraphNode;
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
book: string;
|
book: string;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EditPost(props: EditPostProps & RouteComponentProps): ReactElement {
|
export function EditPost(props: EditPostProps & RouteComponentProps): ReactElement {
|
||||||
const { note, book, noteId, api, ship, history, s3 } = props;
|
const { note, book, noteId, api, ship, history, storage } = props;
|
||||||
const [revNum, title, body] = getLatestRevision(note);
|
const [revNum, title, body] = getLatestRevision(note);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export function EditPost(props: EditPostProps & RouteComponentProps): ReactEleme
|
|||||||
cancel
|
cancel
|
||||||
history={history}
|
history={history}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
s3={s3}
|
storage={storage}
|
||||||
submitLabel="Update"
|
submitLabel="Update"
|
||||||
loadingText="Updating..."
|
loadingText="Updating..."
|
||||||
/>
|
/>
|
||||||
|
@ -16,8 +16,8 @@ import 'codemirror/lib/codemirror.css';
|
|||||||
import { Box } from '@tlon/indigo-react';
|
import { Box } from '@tlon/indigo-react';
|
||||||
import { useFileDrag } from '~/logic/lib/useDrag';
|
import { useFileDrag } from '~/logic/lib/useDrag';
|
||||||
import SubmitDragger from '~/views/components/SubmitDragger';
|
import SubmitDragger from '~/views/components/SubmitDragger';
|
||||||
import useS3 from '~/logic/lib/useS3';
|
import useStorage from '~/logic/lib/useStorage';
|
||||||
import { S3State } from '@urbit/api';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
const MARKDOWN_CONFIG = {
|
const MARKDOWN_CONFIG = {
|
||||||
name: 'markdown'
|
name: 'markdown'
|
||||||
@ -28,7 +28,7 @@ interface MarkdownEditorProps {
|
|||||||
value: string;
|
value: string;
|
||||||
onChange: (s: string) => void;
|
onChange: (s: string) => void;
|
||||||
onBlur?: (e: any) => void;
|
onBlur?: (e: any) => void;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PromptIfDirty = () => {
|
const PromptIfDirty = () => {
|
||||||
@ -74,7 +74,7 @@ export function MarkdownEditor(
|
|||||||
[onBlur]
|
[onBlur]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { uploadDefault, canUpload } = useS3(props.s3);
|
const { uploadDefault, canUpload } = useStorage(props.storage);
|
||||||
|
|
||||||
const onFileDrag = useCallback(
|
const onFileDrag = useCallback(
|
||||||
async (files: FileList | File[], e: DragEvent) => {
|
async (files: FileList | File[], e: DragEvent) => {
|
||||||
|
@ -6,7 +6,7 @@ import { MarkdownEditor } from './MarkdownEditor';
|
|||||||
|
|
||||||
export const MarkdownField = ({
|
export const MarkdownField = ({
|
||||||
id,
|
id,
|
||||||
s3,
|
storage,
|
||||||
...rest
|
...rest
|
||||||
}: { id: string } & Parameters<typeof Box>[0]) => {
|
}: { id: string } & Parameters<typeof Box>[0]) => {
|
||||||
const [{ value, onBlur }, { error, touched }, { setValue }] = useField(id);
|
const [{ value, onBlur }, { error, touched }, { setValue }] = useField(id);
|
||||||
@ -28,6 +28,7 @@ export const MarkdownField = ({
|
|||||||
width="100%"
|
width="100%"
|
||||||
display="flex"
|
display="flex"
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
|
color="black"
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
@ -35,7 +36,7 @@ export const MarkdownField = ({
|
|||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={setValue}
|
onChange={setValue}
|
||||||
s3={s3}
|
storage={storage}
|
||||||
/>
|
/>
|
||||||
<ErrorLabel mt="2" hasError={Boolean(error && touched)}>
|
<ErrorLabel mt="2" hasError={Boolean(error && touched)}>
|
||||||
{error}
|
{error}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Box, Text, Col } from '@tlon/indigo-react';
|
import { Box, Text, Col, Anchor } from '@tlon/indigo-react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import bigInt from 'big-integer';
|
import bigInt from 'big-integer';
|
||||||
|
|
||||||
@ -32,6 +32,14 @@ export function Note(props: NoteProps & RouteComponentProps) {
|
|||||||
const { notebook, note, contacts, ship, book, api, rootUrl, baseUrl, group } = props;
|
const { notebook, note, contacts, ship, book, api, rootUrl, baseUrl, group } = props;
|
||||||
const editCommentId = props.match.params.commentId;
|
const editCommentId = props.match.params.commentId;
|
||||||
|
|
||||||
|
const renderers = {
|
||||||
|
link: ({ href, children }) => {
|
||||||
|
return (
|
||||||
|
<Anchor display="inline" target="_blank" href={href}>{children}</Anchor>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const deletePost = async () => {
|
const deletePost = async () => {
|
||||||
setDeleting(true);
|
setDeleting(true);
|
||||||
const indices = [note.post.index];
|
const indices = [note.post.index];
|
||||||
@ -107,7 +115,7 @@ export function Note(props: NoteProps & RouteComponentProps) {
|
|||||||
</Box>
|
</Box>
|
||||||
</Col>
|
</Col>
|
||||||
<Box color="black" className="md" style={{ overflowWrap: 'break-word', overflow: 'hidden' }}>
|
<Box color="black" className="md" style={{ overflowWrap: 'break-word', overflow: 'hidden' }}>
|
||||||
<ReactMarkdown source={body} linkTarget={'_blank'} />
|
<ReactMarkdown source={body} linkTarget={'_blank'} renderers={renderers} />
|
||||||
</Box>
|
</Box>
|
||||||
<NoteNavigation
|
<NoteNavigation
|
||||||
notebook={notebook}
|
notebook={notebook}
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
import { AsyncButton } from '../../../components/AsyncButton';
|
import { AsyncButton } from '../../../components/AsyncButton';
|
||||||
import { Formik, Form, FormikHelpers } from 'formik';
|
import { Formik, Form, FormikHelpers } from 'formik';
|
||||||
import { MarkdownField } from './MarkdownField';
|
import { MarkdownField } from './MarkdownField';
|
||||||
import { S3State } from '@urbit/api';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
interface PostFormProps {
|
interface PostFormProps {
|
||||||
initial: PostFormSchema;
|
initial: PostFormSchema;
|
||||||
@ -21,7 +21,7 @@ interface PostFormProps {
|
|||||||
) => Promise<any>;
|
) => Promise<any>;
|
||||||
submitLabel: string;
|
submitLabel: string;
|
||||||
loadingText: string;
|
loadingText: string;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formSchema = Yup.object({
|
const formSchema = Yup.object({
|
||||||
@ -35,7 +35,7 @@ export interface PostFormSchema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function PostForm(props: PostFormProps) {
|
export function PostForm(props: PostFormProps) {
|
||||||
const { initial, onSubmit, submitLabel, loadingText, s3, cancel, history } = props;
|
const { initial, onSubmit, submitLabel, loadingText, storage, cancel, history } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col width="100%" height="100%" p={[2, 4]}>
|
<Col width="100%" height="100%" p={[2, 4]}>
|
||||||
@ -67,7 +67,7 @@ export function PostForm(props: PostFormProps) {
|
|||||||
>Cancel</Button>}
|
>Cancel</Button>}
|
||||||
</Row>
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
<MarkdownField flexGrow={1} id="body" s3={s3} />
|
<MarkdownField flexGrow={1} id="body" storage={storage} />
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -6,7 +6,8 @@ import { RouteComponentProps } from 'react-router-dom';
|
|||||||
import Note from './Note';
|
import Note from './Note';
|
||||||
import { EditPost } from './EditPost';
|
import { EditPost } from './EditPost';
|
||||||
|
|
||||||
import { GraphNode, Graph, Contacts, Association, S3State, Group } from '@urbit/api';
|
import { GraphNode, Graph, Contacts, Association, Group } from '@urbit/api';
|
||||||
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
interface NoteRoutesProps {
|
interface NoteRoutesProps {
|
||||||
ship: string;
|
ship: string;
|
||||||
@ -20,7 +21,7 @@ interface NoteRoutesProps {
|
|||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
rootUrl?: string;
|
rootUrl?: string;
|
||||||
group: Group;
|
group: Group;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NoteRoutes(props: NoteRoutesProps & RouteComponentProps) {
|
export function NoteRoutes(props: NoteRoutesProps & RouteComponentProps) {
|
||||||
|
@ -9,9 +9,9 @@ import {
|
|||||||
Contacts,
|
Contacts,
|
||||||
Rolodex,
|
Rolodex,
|
||||||
Unreads,
|
Unreads,
|
||||||
S3State
|
|
||||||
} from '@urbit/api';
|
} from '@urbit/api';
|
||||||
import { Center, LoadingSpinner } from '@tlon/indigo-react';
|
import { Center, LoadingSpinner } from '@tlon/indigo-react';
|
||||||
|
import { StorageState } from '~/types';
|
||||||
import bigInt from 'big-integer';
|
import bigInt from 'big-integer';
|
||||||
|
|
||||||
import Notebook from './Notebook';
|
import Notebook from './Notebook';
|
||||||
@ -30,7 +30,7 @@ interface NotebookRoutesProps {
|
|||||||
rootUrl: string;
|
rootUrl: string;
|
||||||
association: Association;
|
association: Association;
|
||||||
associations: Associations;
|
associations: Associations;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NotebookRoutes(
|
export function NotebookRoutes(
|
||||||
@ -77,7 +77,7 @@ export function NotebookRoutes(
|
|||||||
association={props.association}
|
association={props.association}
|
||||||
graph={graph}
|
graph={graph}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -109,7 +109,7 @@ export function NotebookRoutes(
|
|||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
association={props.association}
|
association={props.association}
|
||||||
group={group}
|
group={group}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
{...routeProps}
|
{...routeProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,8 @@ import { RouteComponentProps } from 'react-router-dom';
|
|||||||
import { PostForm, PostFormSchema } from './NoteForm';
|
import { PostForm, PostFormSchema } from './NoteForm';
|
||||||
import { createPost } from '~/logic/api/graph';
|
import { createPost } from '~/logic/api/graph';
|
||||||
import { Graph } from '@urbit/api/graph';
|
import { Graph } from '@urbit/api/graph';
|
||||||
import { Association, S3State } from '@urbit/api';
|
import { Association } from '@urbit/api';
|
||||||
|
import { StorageState } from '~/types';
|
||||||
import { newPost } from '~/logic/lib/publish';
|
import { newPost } from '~/logic/lib/publish';
|
||||||
|
|
||||||
interface NewPostProps {
|
interface NewPostProps {
|
||||||
@ -16,7 +17,7 @@ interface NewPostProps {
|
|||||||
graph: Graph;
|
graph: Graph;
|
||||||
association: Association;
|
association: Association;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NewPost(props: NewPostProps & RouteComponentProps) {
|
export default function NewPost(props: NewPostProps & RouteComponentProps) {
|
||||||
@ -50,7 +51,7 @@ export default function NewPost(props: NewPostProps & RouteComponentProps) {
|
|||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
submitLabel="Publish"
|
submitLabel="Publish"
|
||||||
loadingText="Posting..."
|
loadingText="Posting..."
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
cursor: text;
|
cursor: text;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
background: inherit;
|
||||||
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.publish .CodeMirror * {
|
.publish .CodeMirror * {
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
import GlobalApi from '~/logic/api/global';
|
import GlobalApi from '~/logic/api/global';
|
||||||
import { ImageInput } from '~/views/components/ImageInput';
|
import { ImageInput } from '~/views/components/ImageInput';
|
||||||
import { ColorInput } from '~/views/components/ColorInput';
|
import { ColorInput } from '~/views/components/ColorInput';
|
||||||
import { S3State } from '~/types/s3-update';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
export type BgType = 'none' | 'url' | 'color';
|
export type BgType = 'none' | 'url' | 'color';
|
||||||
|
|
||||||
@ -20,13 +20,13 @@ export function BackgroundPicker({
|
|||||||
bgType,
|
bgType,
|
||||||
bgUrl,
|
bgUrl,
|
||||||
api,
|
api,
|
||||||
s3
|
storage
|
||||||
}: {
|
}: {
|
||||||
bgType: BgType;
|
bgType: BgType;
|
||||||
bgUrl?: string;
|
bgUrl?: string;
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}): ReactElement {
|
}) {
|
||||||
const rowSpace = { my: 0, alignItems: 'center' };
|
const rowSpace = { my: 0, alignItems: 'center' };
|
||||||
const colProps = { my: 3, mr: 4, gapY: 1 };
|
const colProps = { my: 3, mr: 4, gapY: 1 };
|
||||||
return (
|
return (
|
||||||
@ -39,7 +39,7 @@ export function BackgroundPicker({
|
|||||||
<ImageInput
|
<ImageInput
|
||||||
ml="5"
|
ml="5"
|
||||||
api={api}
|
api={api}
|
||||||
s3={s3}
|
storage={storage}
|
||||||
id="bgUrl"
|
id="bgUrl"
|
||||||
placeholder="Drop or upload a file, or paste a link here"
|
placeholder="Drop or upload a file, or paste a link here"
|
||||||
name="bgUrl"
|
name="bgUrl"
|
||||||
|
@ -11,7 +11,7 @@ import * as Yup from "yup";
|
|||||||
|
|
||||||
import GlobalApi from "~/logic/api/global";
|
import GlobalApi from "~/logic/api/global";
|
||||||
import { uxToHex } from "~/logic/lib/util";
|
import { uxToHex } from "~/logic/lib/util";
|
||||||
import { S3State, BackgroundConfig } from "~/types";
|
import { S3State, BackgroundConfig, StorageState } from "~/types";
|
||||||
import { BackgroundPicker, BgType } from "./BackgroundPicker";
|
import { BackgroundPicker, BgType } from "./BackgroundPicker";
|
||||||
import useSettingsState, { SettingsState, selectSettingsState } from "~/logic/state/settings";
|
import useSettingsState, { SettingsState, selectSettingsState } from "~/logic/state/settings";
|
||||||
import {AsyncButton} from "~/views/components/AsyncButton";
|
import {AsyncButton} from "~/views/components/AsyncButton";
|
||||||
@ -36,13 +36,13 @@ interface FormSchema {
|
|||||||
|
|
||||||
interface DisplayFormProps {
|
interface DisplayFormProps {
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsSel = selectSettingsState(["display"]);
|
const settingsSel = selectSettingsState(["display"]);
|
||||||
|
|
||||||
export default function DisplayForm(props: DisplayFormProps) {
|
export default function DisplayForm(props: DisplayFormProps) {
|
||||||
const { api, s3 } = props;
|
const { api, storage } = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
display: {
|
display: {
|
||||||
@ -108,7 +108,7 @@ export default function DisplayForm(props: DisplayFormProps) {
|
|||||||
bgType={props.values.bgType}
|
bgType={props.values.bgType}
|
||||||
bgUrl={props.values.bgUrl}
|
bgUrl={props.values.bgUrl}
|
||||||
api={api}
|
api={api}
|
||||||
s3={s3}
|
storage={storage}
|
||||||
/>
|
/>
|
||||||
<Label>Theme</Label>
|
<Label>Theme</Label>
|
||||||
<Radio name="theme" id="light" label="Light"/>
|
<Radio name="theme" id="light" label="Light"/>
|
||||||
|
@ -15,6 +15,7 @@ import GlobalApi from "~/logic/api/global";
|
|||||||
import { BucketList } from "./BucketList";
|
import { BucketList } from "./BucketList";
|
||||||
import { S3State } from '~/types/s3-update';
|
import { S3State } from '~/types/s3-update';
|
||||||
import { BackButton } from './BackButton';
|
import { BackButton } from './BackButton';
|
||||||
|
import {StorageState} from '~/types';
|
||||||
|
|
||||||
interface FormSchema {
|
interface FormSchema {
|
||||||
s3bucket: string;
|
s3bucket: string;
|
||||||
@ -26,11 +27,12 @@ interface FormSchema {
|
|||||||
|
|
||||||
interface S3FormProps {
|
interface S3FormProps {
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function S3Form(props: S3FormProps): ReactElement {
|
export default function S3Form(props: S3FormProps): ReactElement {
|
||||||
const { api, s3 } = props;
|
const { api, storage } = props;
|
||||||
|
const { s3 } = storage;
|
||||||
|
|
||||||
const onSubmit = useCallback(
|
const onSubmit = useCallback(
|
||||||
(values: FormSchema) => {
|
(values: FormSchema) => {
|
||||||
@ -48,6 +50,7 @@ export default function S3Form(props: S3FormProps): ReactElement {
|
|||||||
},
|
},
|
||||||
[api, s3]
|
[api, s3]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Col p="5" pt="4" borderBottom="1" borderBottomColor="washedGray">
|
<Col p="5" pt="4" borderBottom="1" borderBottomColor="washedGray">
|
||||||
|
@ -116,10 +116,10 @@ export default function SettingsScreen(props: any) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{hash === "display" && (
|
{hash === "display" && (
|
||||||
<DisplayForm s3={props.s3} api={props.api} />
|
<DisplayForm storage={props.storage} api={props.api} />
|
||||||
)}
|
)}
|
||||||
{hash === "s3" && (
|
{hash === "s3" && (
|
||||||
<S3Form s3={props.s3} api={props.api} />
|
<S3Form storage={props.storage} api={props.api} />
|
||||||
)}
|
)}
|
||||||
{hash === "leap" && (
|
{hash === "leap" && (
|
||||||
<LeapSettings api={props.api} />
|
<LeapSettings api={props.api} />
|
||||||
|
@ -67,6 +67,7 @@ export default class TermApp extends Component {
|
|||||||
backgroundColor='white'
|
backgroundColor='white'
|
||||||
width='100%'
|
width='100%'
|
||||||
minHeight='0'
|
minHeight='0'
|
||||||
|
minWidth='0'
|
||||||
color='washedGray'
|
color='washedGray'
|
||||||
borderRadius='2'
|
borderRadius='2'
|
||||||
mx={['0','3']}
|
mx={['0','3']}
|
||||||
|
@ -13,6 +13,7 @@ export class History extends Component {
|
|||||||
<Box
|
<Box
|
||||||
height='100%'
|
height='100%'
|
||||||
minHeight='0'
|
minHeight='0'
|
||||||
|
minWidth='0'
|
||||||
display='flex'
|
display='flex'
|
||||||
flexDirection='column-reverse'
|
flexDirection='column-reverse'
|
||||||
overflowY='scroll'
|
overflowY='scroll'
|
||||||
|
@ -11,20 +11,20 @@ import {
|
|||||||
BaseInput
|
BaseInput
|
||||||
} from '@tlon/indigo-react';
|
} from '@tlon/indigo-react';
|
||||||
|
|
||||||
import { S3State } from '~/types/s3-update';
|
import { StorageState } from '~/types';
|
||||||
import useS3 from '~/logic/lib/useS3';
|
import useStorage from '~/logic/lib/useStorage';
|
||||||
|
|
||||||
type ImageInputProps = Parameters<typeof Box>[0] & {
|
type ImageInputProps = Parameters<typeof Box>[0] & {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ImageInput(props: ImageInputProps): ReactElement {
|
export function ImageInput(props: ImageInputProps): ReactElement {
|
||||||
const { id, label, s3, caption, placeholder } = props;
|
const { id, label, storage, caption, placeholder } = props;
|
||||||
|
|
||||||
const { uploadDefault, canUpload, uploading } = useS3(s3);
|
const { uploadDefault, canUpload, uploading } = useStorage(storage);
|
||||||
|
|
||||||
const [field, meta, { setValue, setError }] = useField(id);
|
const [field, meta, { setValue, setError }] = useField(id);
|
||||||
|
|
||||||
|
@ -24,20 +24,50 @@ interface RendererProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface VirtualScrollerProps<T> {
|
interface VirtualScrollerProps<T> {
|
||||||
|
/**
|
||||||
|
* Start scroll from
|
||||||
|
*/
|
||||||
origin: 'top' | 'bottom';
|
origin: 'top' | 'bottom';
|
||||||
|
/**
|
||||||
|
* Load more of the graph
|
||||||
|
*
|
||||||
|
* @returns boolean whether or not the graph is now fully loaded
|
||||||
|
*/
|
||||||
loadRows(newer: boolean): Promise<boolean>;
|
loadRows(newer: boolean): Promise<boolean>;
|
||||||
|
/**
|
||||||
|
* The data to iterate over
|
||||||
|
*/
|
||||||
data: BigIntOrderedMap<T>;
|
data: BigIntOrderedMap<T>;
|
||||||
id: string;
|
/**
|
||||||
|
* The component to render the items
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
*
|
||||||
|
* This component must be referentially stable, so either use `useCallback` or
|
||||||
|
* a instance method. It must also forward the DOM ref from its root DOM node
|
||||||
|
*/
|
||||||
renderer: (props: RendererProps) => JSX.Element | null;
|
renderer: (props: RendererProps) => JSX.Element | null;
|
||||||
onStartReached?(): void;
|
onStartReached?(): void;
|
||||||
onEndReached?(): void;
|
onEndReached?(): void;
|
||||||
size: number;
|
size: number;
|
||||||
pendingSize: number;
|
pendingSize: number;
|
||||||
totalSize: number;
|
totalSize: number;
|
||||||
|
/**
|
||||||
|
* Average height of a single rendered item
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This is used primarily to calculate how many items should be onscreen. If
|
||||||
|
* size is variable, err on the lower side.
|
||||||
|
*/
|
||||||
averageHeight: number;
|
averageHeight: number;
|
||||||
|
/**
|
||||||
|
* The offset to begin rendering at, on load.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This is only looked up once, on component creation. Subsequent changes to
|
||||||
|
* this prop will have no effect
|
||||||
|
*/
|
||||||
offset: number;
|
offset: number;
|
||||||
onCalculateVisibleItems?(visibleItems: BigIntOrderedMap<T>): void;
|
|
||||||
onScroll?({ scrollTop, scrollHeight, windowHeight }): void;
|
|
||||||
style?: any;
|
style?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +92,12 @@ const ZONE_SIZE = IS_IOS ? 10 : 40;
|
|||||||
// nb: in this file, an index refers to a BigInteger and an offset refers to a
|
// nb: in this file, an index refers to a BigInteger and an offset refers to a
|
||||||
// number used to index a listified BigIntOrderedMap
|
// number used to index a listified BigIntOrderedMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A virtualscroller for a `BigIntOrderedMap`.
|
||||||
|
*
|
||||||
|
* VirtualScroller does not clean up or reset itself, so please use `key`
|
||||||
|
* to ensure a new instance is created for each BigIntOrderedMap
|
||||||
|
*/
|
||||||
export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T>, VirtualScrollerState<T>> {
|
export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T>, VirtualScrollerState<T>> {
|
||||||
/**
|
/**
|
||||||
* A reference to our scroll container
|
* A reference to our scroll container
|
||||||
@ -88,8 +124,6 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
|||||||
*/
|
*/
|
||||||
private saveDepth = 0;
|
private saveDepth = 0;
|
||||||
|
|
||||||
private isUpdating = false;
|
|
||||||
|
|
||||||
private scrollLocked = true;
|
private scrollLocked = true;
|
||||||
|
|
||||||
private pageSize = 50;
|
private pageSize = 50;
|
||||||
@ -98,7 +132,6 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
|||||||
|
|
||||||
private scrollRef: HTMLElement | null = null;
|
private scrollRef: HTMLElement | null = null;
|
||||||
|
|
||||||
|
|
||||||
private loaded = {
|
private loaded = {
|
||||||
top: false,
|
top: false,
|
||||||
bottom: false
|
bottom: false
|
||||||
@ -186,7 +219,6 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log('reflow', `from: ${this.startOffset()} to: ${newOffset}`);
|
log('reflow', `from: ${this.startOffset()} to: ${newOffset}`);
|
||||||
this.isUpdating = true;
|
|
||||||
|
|
||||||
const { data, onCalculateVisibleItems } = this.props;
|
const { data, onCalculateVisibleItems } = this.props;
|
||||||
const visibleItems = new BigIntOrderedMap<any>(
|
const visibleItems = new BigIntOrderedMap<any>(
|
||||||
@ -195,14 +227,12 @@ export default class VirtualScroller<T> extends Component<VirtualScrollerProps<T
|
|||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
onCalculateVisibleItems ? onCalculateVisibleItems(visibleItems) : null;
|
|
||||||
this.setState({
|
this.setState({
|
||||||
visibleItems,
|
visibleItems,
|
||||||
}, () => {
|
}, () => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.restore();
|
this.restore();
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.isUpdating = false;
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import useS3 from '~/logic/lib/useS3';
|
|
||||||
|
|
||||||
const withS3 = (Component, params = {}) => {
|
|
||||||
return React.forwardRef((props: any, ref) => {
|
|
||||||
const s3 = useS3(props.s3, params);
|
|
||||||
|
|
||||||
return <Component ref={ref} {...s3} {...props} />;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withS3;
|
|
12
pkg/interface/src/views/components/withStorage.tsx
Normal file
12
pkg/interface/src/views/components/withStorage.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import useStorage from '~/logic/lib/useStorage';
|
||||||
|
|
||||||
|
const withStorage = (Component, params = {}) => {
|
||||||
|
return React.forwardRef((props: any, ref) => {
|
||||||
|
const storage = useStorage(props.storage, params);
|
||||||
|
|
||||||
|
return <Component ref={ref} {...storage} {...props} />;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withStorage;
|
@ -21,7 +21,7 @@ import { ColorInput } from '~/views/components/ColorInput';
|
|||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { uxToHex } from '~/logic/lib/util';
|
import { uxToHex } from '~/logic/lib/util';
|
||||||
import { ImageInput } from '~/views/components/ImageInput';
|
import { ImageInput } from '~/views/components/ImageInput';
|
||||||
import { S3State } from '~/types/s3-update';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
interface FormSchema {
|
interface FormSchema {
|
||||||
title: string;
|
title: string;
|
||||||
@ -44,11 +44,11 @@ interface GroupAdminSettingsProps {
|
|||||||
group: Group;
|
group: Group;
|
||||||
association: Association;
|
association: Association;
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GroupAdminSettings(props: GroupAdminSettingsProps) {
|
export function GroupAdminSettings(props: GroupAdminSettingsProps) {
|
||||||
const { group, association, s3 } = props;
|
const { group, association, storage } = props;
|
||||||
const { metadata } = association;
|
const { metadata } = association;
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const currentPrivate = 'invite' in props.group.policy;
|
const currentPrivate = 'invite' in props.group.policy;
|
||||||
@ -131,7 +131,7 @@ return null;
|
|||||||
caption="A picture for your group"
|
caption="A picture for your group"
|
||||||
placeholder="Enter URL"
|
placeholder="Enter URL"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
s3={s3}
|
storage={storage}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="isPrivate"
|
id="isPrivate"
|
||||||
|
@ -11,7 +11,7 @@ import { GroupPersonalSettings } from './Personal';
|
|||||||
import { GroupChannelSettings } from './Channels';
|
import { GroupChannelSettings } from './Channels';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { resourceFromPath, roleForShip } from '~/logic/lib/group';
|
import { resourceFromPath, roleForShip } from '~/logic/lib/group';
|
||||||
import { S3State } from '~/types';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
const Section = ({ children }) => (
|
const Section = ({ children }) => (
|
||||||
<Box boxShadow="inset 0px 1px 0px rgba(0, 0, 0, 0.2)">{children}</Box>
|
<Box boxShadow="inset 0px 1px 0px rgba(0, 0, 0, 0.2)">{children}</Box>
|
||||||
@ -23,7 +23,7 @@ interface GroupSettingsProps {
|
|||||||
associations: Associations;
|
associations: Associations;
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
notificationsGroupConfig: GroupNotificationsConfig;
|
notificationsGroupConfig: GroupNotificationsConfig;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
}
|
}
|
||||||
export function GroupSettings(props: GroupSettingsProps) {
|
export function GroupSettings(props: GroupSettingsProps) {
|
||||||
|
@ -70,7 +70,7 @@ export function GroupsPane(props: GroupsPaneProps) {
|
|||||||
association={groupAssociation!}
|
association={groupAssociation!}
|
||||||
group={group!}
|
group={group!}
|
||||||
api={api}
|
api={api}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
notificationsGroupConfig={props.notificationsGroupConfig}
|
notificationsGroupConfig={props.notificationsGroupConfig}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import { DeleteGroup } from './DeleteGroup';
|
|||||||
import { resourceFromPath } from '~/logic/lib/group';
|
import { resourceFromPath } from '~/logic/lib/group';
|
||||||
import { ModalOverlay } from '~/views/components/ModalOverlay';
|
import { ModalOverlay } from '~/views/components/ModalOverlay';
|
||||||
import { SidebarItem } from '~/views/landscape/components/SidebarItem';
|
import { SidebarItem } from '~/views/landscape/components/SidebarItem';
|
||||||
import { S3State } from '~/types';
|
import { StorageState } from '~/types';
|
||||||
|
|
||||||
export function PopoverRoutes(
|
export function PopoverRoutes(
|
||||||
props: {
|
props: {
|
||||||
@ -24,7 +24,7 @@ export function PopoverRoutes(
|
|||||||
group: Group;
|
group: Group;
|
||||||
association: Association;
|
association: Association;
|
||||||
associations: Associations;
|
associations: Associations;
|
||||||
s3: S3State;
|
storage: StorageState;
|
||||||
api: GlobalApi;
|
api: GlobalApi;
|
||||||
notificationsGroupConfig: GroupNotificationsConfig;
|
notificationsGroupConfig: GroupNotificationsConfig;
|
||||||
rootIdentity: Contact;
|
rootIdentity: Contact;
|
||||||
@ -128,7 +128,7 @@ export function PopoverRoutes(
|
|||||||
api={props.api}
|
api={props.api}
|
||||||
notificationsGroupConfig={props.notificationsGroupConfig}
|
notificationsGroupConfig={props.notificationsGroupConfig}
|
||||||
associations={props.associations}
|
associations={props.associations}
|
||||||
s3={props.s3}
|
storage={props.storage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{view === 'participants' && (
|
{view === 'participants' && (
|
||||||
|
53
sh/poke-gcp-account-json
Executable file
53
sh/poke-gcp-account-json
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def herb_poke_gcp_setting(pier, key, val):
|
||||||
|
"""
|
||||||
|
Poke a value into settings-store under the %gcp-store bucket.
|
||||||
|
|
||||||
|
This does not sanitize or check its inputs. Please make sure they are
|
||||||
|
correct before calling this function.
|
||||||
|
|
||||||
|
:pier: Pier of the ship to poke.
|
||||||
|
:key: Key to poke. Must be a @tas (i.e. include the '%').
|
||||||
|
:val: Value to poke. Must be a @t. (will be passed through crude_t.)
|
||||||
|
"""
|
||||||
|
print('herb_poke ' + key)
|
||||||
|
# XXX use +same because herb's cell parser is cursed.
|
||||||
|
poke_arg = "(same %put-entry %gcp-store {} %s {})".format(
|
||||||
|
key, crude_t(val))
|
||||||
|
return subprocess.run(['herb', pier, '-p', 'settings-store', '-d',
|
||||||
|
poke_arg, '-m', 'settings-event'],
|
||||||
|
check=True)
|
||||||
|
|
||||||
|
def crude_t(pin):
|
||||||
|
"""
|
||||||
|
Very crude, bad, dangerous, and evil @t transform.
|
||||||
|
|
||||||
|
Puts single quotes around the string. Escapes instances of single quote and
|
||||||
|
backslash within the string, and turns newlines into \0a.
|
||||||
|
"""
|
||||||
|
replaces = [(r'\\', r'\\\\'), ("'", r"\\'"), ("\n", r'\\0a')]
|
||||||
|
for pattern, replace in replaces:
|
||||||
|
pin = re.sub(pattern, replace, pin, flags=re.MULTILINE)
|
||||||
|
return "'{}'".format(pin)
|
||||||
|
|
||||||
|
def read_gcp_json(keyfile):
|
||||||
|
with open(keyfile, 'r') as f:
|
||||||
|
return json.loads(f.read())
|
||||||
|
|
||||||
|
def main():
|
||||||
|
pier, keyfile = sys.argv[1:]
|
||||||
|
obj = read_gcp_json(keyfile)
|
||||||
|
herb_poke_gcp_setting(pier, '%token-uri', obj['token_uri'])
|
||||||
|
herb_poke_gcp_setting(pier, '%client-email', obj['client_email'])
|
||||||
|
herb_poke_gcp_setting(pier, '%private-key-id', obj['private_key_id'])
|
||||||
|
herb_poke_gcp_setting(pier, '%private-key', obj['private_key'])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user