From fcfcf95aed74c24b014256498a7a0a337b998f2f Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Mon, 1 Jun 2020 17:07:31 -0400 Subject: [PATCH 001/543] graph-store: structure compiles --- pkg/arvo/app/graph-store.hoon | 73 +++++++++++++++++++++++++++++++++++ pkg/arvo/sur/graph-store.hoon | 35 +++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 pkg/arvo/app/graph-store.hoon create mode 100644 pkg/arvo/sur/graph-store.hoon diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon new file mode 100644 index 0000000000..f974d86288 --- /dev/null +++ b/pkg/arvo/app/graph-store.hoon @@ -0,0 +1,73 @@ +/+ store=graph-store, default-agent, dbug +|% ++$ card card:agent:gall ++$ versioned-state + $% state-0 + == ++$ state-0 [%0 network:store] +++ ordered-graph ((ordered-map ,time ,node:store) gth) +-- +:: +=| state-0 +=* state - +:: +%- agent:dbug +^- agent:gall +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init [~ this] +++ on-save !>(state) +++ on-load + |= old=vase + ^- (quip card _this) + [~ this(state !<(state-0 old))] +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %graph-action (graph-action !<(action:store vase)) + == + [cards this] + :: + ++ graph-action + |= =action:store + ^- (quip card _state) + [~ state] + -- +:: +++ on-watch + |= =path + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =/ cards=(list card) + ?+ path (on-watch:def path) + [%all ~] (give [%initial graphs tags tag-queries]) + [%keys ~] (give [%keys ~(key by graphs)]) + == + [cards this] + :: + ++ give + |= =update:store + ^- (list card) + [%give %fact ~ [%graph-update !>(update)]]~ + -- +:: +++ on-peek + |= =path + ^- (unit (unit cage)) + ?+ path (on-peek:def path) + [%x %keys ~] ``noun+!>(~(key by graphs)) + == +:: +++ on-arvo on-arvo:def +++ on-agent on-agent:def +++ on-leave on-leave:def +++ on-fail on-fail:def +-- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon new file mode 100644 index 0000000000..cb6ce7e417 --- /dev/null +++ b/pkg/arvo/sur/graph-store.hoon @@ -0,0 +1,35 @@ +/- *post +|% ++$ network + $: graphs=(map resource graph) + tags=(set term) + tag-queries=(map term resources) + == +:: ++$ internal-graph (tree [key=time val=node]) ++$ graph + $~ [%empty ~] + $% [%graph u=internal-graph] + [%empty ~] + == ++$ node [=post replies=graph] ++$ action + $% [%add-graph =resource =graph] + [%remove-graph =resource] + :: + [%add-nodes uids=(set [=uid =node])] + [%remove-nodes uids=(set uid)] + :: + [%add-signatures =uid =signatures] + [%remove-signatures =uid =signatures] + :: + [%add-tag =term =resources] + [%remove-tag =term =resources] + == +:: ++$ update + $% [%keys =resources] + [%initial =network] + action + == +-- From 83ec7eae246f4962cdac2d397191fb0eca224d49 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 2 Jun 2020 15:44:22 -0400 Subject: [PATCH 002/543] graph-store: cleaned up structures --- pkg/arvo/app/graph-store.hoon | 1 - pkg/arvo/sur/graph-store.hoon | 26 +++++++++++++++++++------- pkg/arvo/sur/post.hoon | 26 ++++++++++++++++++++++++++ pkg/arvo/sur/resource.hoon | 10 ++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 pkg/arvo/sur/post.hoon create mode 100644 pkg/arvo/sur/resource.hoon diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index f974d86288..8a02cf243a 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -5,7 +5,6 @@ $% state-0 == +$ state-0 [%0 network:store] -++ ordered-graph ((ordered-map ,time ,node:store) gth) -- :: =| state-0 diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index cb6ce7e417..83e3c0de61 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -1,23 +1,35 @@ /- *post |% +++ mop + |* [key=mold value=mold] + |= ord=$-([key key] ?) + |= a=* + =/ b ;;((tree [key=key val=value]) a) + ?> (check-balance:((ordered-map key value) ord) b) + b +:: +$ network $: graphs=(map resource graph) tags=(set term) tag-queries=(map term resources) == :: -+$ internal-graph (tree [key=time val=node]) -+$ graph - $~ [%empty ~] - $% [%graph u=internal-graph] - [%empty ~] ++$ graph ((mop atom node) lte) ++$ internal-graph + $~ [%not-loaded ~] + $% :: + :: a graph and timestamp of when it was last modified + [%graph p=graph q=time] + [%empty-when-fetched p=time] + [%not-loaded ~] == -+$ node [=post replies=graph] +:: ++$ node [=post children=internal-graph] +$ action $% [%add-graph =resource =graph] [%remove-graph =resource] :: - [%add-nodes uids=(set [=uid =node])] + [%add-nodes nodes=(map uid node)] [%remove-nodes uids=(set uid)] :: [%add-signatures =uid =signatures] diff --git a/pkg/arvo/sur/post.hoon b/pkg/arvo/sur/post.hoon new file mode 100644 index 0000000000..72905b43ef --- /dev/null +++ b/pkg/arvo/sur/post.hoon @@ -0,0 +1,26 @@ +/- *resource +|% ++$ atom @ ++$ index (list atom) ++$ uid [=resource =index] +:: ++$ hash @ux ++$ signature @ux ++$ signatures (set signature) ++$ post + $: author=ship + =hash + =index + contents=(list content) + signatures=[p=signatures q=hash] + time-sent=time + == +:: ++$ content + $% [%text =cord] + [%url =cord] + [%code expression=cord output=(list tank)] + [%reference =uid] + :: [%cage =cage] + == +-- diff --git a/pkg/arvo/sur/resource.hoon b/pkg/arvo/sur/resource.hoon new file mode 100644 index 0000000000..c4a43ddba1 --- /dev/null +++ b/pkg/arvo/sur/resource.hoon @@ -0,0 +1,10 @@ +|% ++$ resource [=entity =term] ++$ resources (set resource) +:: ++$ entity + $@ ship + $% [%ships ships=(set ship)] + :: [%ring ...] + == +-- From e52779a35664e8e73c7625b5962a338089819ef7 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 5 Jun 2020 15:22:36 -0400 Subject: [PATCH 003/543] graph-store: first pass at writing %add-nodes poke --- pkg/arvo/app/graph-store.hoon | 134 +++++++++++++++++++++++++++++++++- pkg/arvo/lib/graph-store.hoon | 33 +++++++++ pkg/arvo/sur/graph-store.hoon | 4 +- pkg/arvo/sur/post.hoon | 6 +- pkg/arvo/sur/resource.hoon | 3 +- 5 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 pkg/arvo/lib/graph-store.hoon diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 8a02cf243a..1e68d9473f 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -21,6 +21,7 @@ ++ on-load |= old=vase ^- (quip card _this) + ::[~ this] [~ this(state !<(state-0 old))] :: ++ on-poke @@ -37,7 +38,138 @@ ++ graph-action |= =action:store ^- (quip card _state) - [~ state] + |^ + ?- -.action + %add-graph (add-graph +.action) + %remove-graph (remove-graph +.action) + %add-nodes (add-nodes +.action) + %remove-nodes (remove-nodes +.action) + %add-signatures (add-signatures +.action) + %remove-signatures (remove-signatures +.action) + %add-tag (add-tag +.action) + %remove-tag (remove-tag +.action) + == + :: + ++ add-graph + |= [=resource:store =graph:store] + ^- (quip card _state) + ?< (~(has by graphs) resource) + :- (give [/all /keys ~] [%add-graph resource graph]) + state(graphs (~(put by graphs) resource graph)) + :: + ++ remove-graph + |= =resource:store + ^- (quip card _state) + ?> (~(has by graphs) resource) + :- (give [/all /keys ~] [%remove-graph resource]) + state(graphs (~(del by graphs) resource)) + :: + ++ add-nodes + |= nodes=(map resource:store (map index:store node:store)) + ^- (quip card _state) + =/ resource-list ~(tap by nodes) + |^ + ?~ resource-list + :_ state + (give [/all]~ [%add-nodes nodes]) + =* resource -.i.resource-list + =* indexed-nodes +.i.resource-list + =/ graph=(unit graph) (~(get by graphs) resource) + ?~ graph + ~| "graph {} does not exist to add a node to!" + $(resource-list t.resource-list) + %_ $ + resource-list t.resource-list + graphs + %+ ~(put by graphs) + resource + (add-node-list resource u.graph ~(tap by indexed-nodes)) + == + :: + ++ add-node-list + |= $: =resource:store + =graph:store + node-list=(list [index:store node:store]) + == + ^- graph:store + |- + ?~ node-list graph + =* index -.i.node-list + =* node +.i.node-list + %_ $ + node-list t.node-list + graph (add-node-at-index graph index node) + == + :: + ++ add-node-at-index + |= [=graph:store =index:store =node:store] + ^- graph:store + ?~ index graph + =* atom i.index + :: last index in list + ?~ t.index (put:orm graph atom node) + :: multiple indices left in list + :: TODO: replace normal map function with ordered-map version + :: of get. look at find-ducts in behn + =/ parent=(unit node) (~(get by graph) atom) + ?~ parent + ~| "{} does not exist to add a node to!" + graph + ?+ -.children.u.parent + :: replace empty graph with graph containing one child + %^ put:orm + graph + atom + %_ u.parent + children + [%graph $(graph (gas:orm ~ ~), index t.index) now.bowl] + == + :: + %graph + :: recurse into children + %^ put:orm + graph + atom + %_ u.parent + p.children $(graph p.children.u.parent, index t.index) + q.children now.bowl + == + == + :: + ++ orm ((ordered-map atom:store node:store) lth) + -- + :: + ++ remove-nodes + |= uids=(set uid:store) + ^- (quip card _state) + [~ state] + :: + ++ add-signatures + |= [=uid:store =signatures:store] + ^- (quip card _state) + [~ state] + :: + ++ remove-signatures + |= [=uid:store =signatures:store] + ^- (quip card _state) + [~ state] + :: + ++ add-tag + |= [=term =resources:store] + ^- (quip card _state) + [~ state] + :: + ++ remove-tag + |= [=term =resources:store] + ^- (quip card _state) + [~ state] + :: + :: + ++ give + |= [paths=(list path) =update:store] + ^- (list card) + [%give %fact paths [%graph-update !>(update)]]~ + -- -- :: ++ on-watch diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon new file mode 100644 index 0000000000..7a3f69ea27 --- /dev/null +++ b/pkg/arvo/lib/graph-store.hoon @@ -0,0 +1,33 @@ +/- sur=graph-store, pos=post, res=resource +^? +=< [sur .] +=< [pos .] +=< [res .] +=, sur +=, pos +=, res +|% +++ enjs + =, enjs:format + |% + ++ update + |= upd=^update + ^- json + |^ (frond %graph-update (pairs ~[(encode upd)])) + :: + ++ encode + |= upd=^update + ^- [cord json] + [*cord *json] + -- + -- +:: +++ dejs + =, dejs:format + |% + ++ action + |= =json + ^- ^action + !! + -- +-- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index 83e3c0de61..f1eccab029 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -14,7 +14,7 @@ tag-queries=(map term resources) == :: -+$ graph ((mop atom node) lte) ++$ graph ((mop atom node) lth) +$ internal-graph $~ [%not-loaded ~] $% :: @@ -29,7 +29,7 @@ $% [%add-graph =resource =graph] [%remove-graph =resource] :: - [%add-nodes nodes=(map uid node)] + [%add-nodes nodes=(map resource (map index node))] [%remove-nodes uids=(set uid)] :: [%add-signatures =uid =signatures] diff --git a/pkg/arvo/sur/post.hoon b/pkg/arvo/sur/post.hoon index 72905b43ef..f187c3d465 100644 --- a/pkg/arvo/sur/post.hoon +++ b/pkg/arvo/sur/post.hoon @@ -4,7 +4,11 @@ +$ index (list atom) +$ uid [=resource =index] :: -+$ hash @ux ++$ hash + $% [%sha256 p=@ux] + [%murmur3 p=@ux] + == +:: +$ signature @ux +$ signatures (set signature) +$ post diff --git a/pkg/arvo/sur/resource.hoon b/pkg/arvo/sur/resource.hoon index c4a43ddba1..b0b57e8217 100644 --- a/pkg/arvo/sur/resource.hoon +++ b/pkg/arvo/sur/resource.hoon @@ -4,7 +4,8 @@ :: +$ entity $@ ship - $% [%ships ships=(set ship)] + $% [%empty ~] + :: [%ships ships=(set ship)] :: [%ring ...] == -- From 8c2d9127f31900f5db78d076422043c293233191 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 5 Jun 2020 16:11:04 -0400 Subject: [PATCH 004/543] graph-store: add-nodes compiles --- pkg/arvo/app/graph-store.hoon | 32 ++-- pkg/arvo/lib/or-map.hoon | 313 ++++++++++++++++++++++++++++++++++ pkg/arvo/sur/graph-store.hoon | 6 +- 3 files changed, 334 insertions(+), 17 deletions(-) create mode 100644 pkg/arvo/lib/or-map.hoon diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 1e68d9473f..be7615db7a 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -1,10 +1,12 @@ -/+ store=graph-store, default-agent, dbug +/+ store=graph-store, *or-map, default-agent, dbug |% +$ card card:agent:gall +$ versioned-state $% state-0 == +$ state-0 [%0 network:store] +:: +++ orm ((or-map atom:store node:store) lth) -- :: =| state-0 @@ -73,10 +75,10 @@ :_ state (give [/all]~ [%add-nodes nodes]) =* resource -.i.resource-list - =* indexed-nodes +.i.resource-list - =/ graph=(unit graph) (~(get by graphs) resource) + =/ indexed-nodes=(map index:store node:store) +.i.resource-list + =/ graph=(unit graph:store) (~(get by graphs) resource) ?~ graph - ~| "graph {} does not exist to add a node to!" + ~& "graph {} does not exist to add a node to!" $(resource-list t.resource-list) %_ $ resource-list t.resource-list @@ -107,36 +109,38 @@ ?~ index graph =* atom i.index :: last index in list + :: ?~ t.index (put:orm graph atom node) :: multiple indices left in list - :: TODO: replace normal map function with ordered-map version - :: of get. look at find-ducts in behn - =/ parent=(unit node) (~(get by graph) atom) + :: + =/ parent=(unit node:store) (get:orm graph atom) ?~ parent - ~| "{} does not exist to add a node to!" + ~& "index does not exist to add a node to!" graph - ?+ -.children.u.parent + =/ par=node:store (need parent) + ?+ -.children.par :: replace empty graph with graph containing one child + :: %^ put:orm graph atom - %_ u.parent + %= par children + ^- internal-graph:store [%graph $(graph (gas:orm ~ ~), index t.index) now.bowl] == :: %graph :: recurse into children + :: %^ put:orm graph atom - %_ u.parent - p.children $(graph p.children.u.parent, index t.index) + %_ par + p.children $(graph p.children.par, index t.index) q.children now.bowl == == - :: - ++ orm ((ordered-map atom:store node:store) lth) -- :: ++ remove-nodes diff --git a/pkg/arvo/lib/or-map.hoon b/pkg/arvo/lib/or-map.hoon new file mode 100644 index 0000000000..060b0f631f --- /dev/null +++ b/pkg/arvo/lib/or-map.hoon @@ -0,0 +1,313 @@ +|% +:: +:: $mk-item: constructor for +ordered-map item type +:: +++ mk-item |$ [key val] [key=key val=val] +:: +ordered-map: treap with user-specified horizontal order +:: +:: Conceptually smaller items go on the left, so the item with the +:: smallest key can be popped off the head. If $key is `@` and +:: .compare is +lte, then the numerically smallest item is the head. +:: +++ or-map + |* [key=mold val=mold] + => |% + +$ item (mk-item key val) + -- + :: +compare: item comparator for horizontal order + :: + |= compare=$-([key key] ?) + |% + :: +check-balance: verify horizontal and vertical orderings + :: + ++ check-balance + =| [l=(unit key) r=(unit key)] + |= a=(tree item) + ^- ? + :: empty tree is valid + :: + ?~ a %.y + :: nonempty trees must maintain several criteria + :: + ?& :: if .n.a is left of .u.l, assert horizontal comparator + :: + ?~(l %.y (compare key.n.a u.l)) + :: if .n.a is right of .u.r, assert horizontal comparator + :: + ?~(r %.y (compare u.r key.n.a)) + :: if .a is not leftmost element, assert vertical order between + :: .l.a and .n.a and recurse to the left with .n.a as right + :: neighbor + :: + ?~(l.a %.y &((mor key.n.a key.n.l.a) $(a l.a, l `key.n.a))) + :: if .a is not rightmost element, assert vertical order + :: between .r.a and .n.a and recurse to the right with .n.a as + :: left neighbor + :: + ?~(r.a %.y &((mor key.n.a key.n.r.a) $(a r.a, r `key.n.a))) + == + :: +put: ordered item insert + :: + ++ put + |= [a=(tree item) =key =val] + ^- (tree item) + :: base case: replace null with single-item tree + :: + ?~ a [n=[key val] l=~ r=~] + :: base case: overwrite existing .key with new .val + :: + ?: =(key.n.a key) a(val.n val) + :: if item goes on left, recurse left then rebalance vertical order + :: + ?: (compare key key.n.a) + =/ l $(a l.a) + ?> ?=(^ l) + ?: (mor key.n.a key.n.l) + a(l l) + l(r a(l r.l)) + :: item goes on right; recurse right then rebalance vertical order + :: + =/ r $(a r.a) + ?> ?=(^ r) + ?: (mor key.n.a key.n.r) + a(r r) + r(l a(r l.r)) + :: +peek: produce head (smallest item) or null + :: + ++ peek + |= a=(tree item) + ^- (unit item) + :: + ?~ a ~ + ?~ l.a `n.a + $(a l.a) + :: +pop: produce .head (smallest item) and .rest or crash if empty + :: + ++ pop + |= a=(tree item) + ^- [head=item rest=(tree item)] + :: + ?~ a !! + ?~ l.a [n.a r.a] + :: + =/ l $(a l.a) + :- head.l + :: load .rest.l back into .a and rebalance + :: + ?: |(?=(~ rest.l) (mor key.n.a key.n.rest.l)) + a(l rest.l) + rest.l(r a(r r.rest.l)) + :: +del: delete .key from .a if it exists, producing value iff deleted + :: + ++ del + |= [a=(tree item) =key] + ^- [(unit val) (tree item)] + :: + ?~ a [~ ~] + :: we found .key at the root; delete and rebalance + :: + ?: =(key key.n.a) + [`val.n.a (nip a)] + :: recurse left or right to find .key + :: + ?: (compare key key.n.a) + =+ [found lef]=$(a l.a) + [found a(l lef)] + =+ [found rig]=$(a r.a) + [found a(r rig)] + :: +nip: remove root; for internal use + :: + ++ nip + |= a=(tree item) + ^- (tree item) + :: + ?> ?=(^ a) + :: delete .n.a; merge and balance .l.a and .r.a + :: + |- ^- (tree item) + ?~ l.a r.a + ?~ r.a l.a + ?: (mor key.n.l.a key.n.r.a) + l.a(r $(l.a r.l.a)) + r.a(l $(r.a l.r.a)) + :: +traverse: stateful partial inorder traversal + :: + :: Mutates .state on each run of .f. Starts at .start key, or if + :: .start is ~, starts at the head (item with smallest key). Stops + :: when .f produces .stop=%.y. Traverses from smaller to larger + :: keys. Each run of .f can replace an item's value or delete the + :: item. + :: + ++ traverse + |* state=mold + |= $: a=(tree item) + =state + f=$-([state item] [(unit val) ? state]) + == + ^+ [state a] + :: acc: accumulator + :: + :: .stop: set to %.y by .f when done traversing + :: .state: threaded through each run of .f and produced by +abet + :: + =/ acc [stop=`?`%.n state=state] + =< abet =< main + |% + ++ abet [state.acc a] + :: +main: main recursive loop; performs a partial inorder traversal + :: + ++ main + ^+ . + :: stop if empty or we've been told to stop + :: + ?~ a . + ?: stop.acc . + :: inorder traversal: left -> node -> right, until .f sets .stop + :: + => left + ?: stop.acc . + => node + ?: stop.acc . + right + :: +node: run .f on .n.a, updating .a, .state, and .stop + :: + ++ node + ^+ . + :: run .f on node, updating .stop.acc and .state.acc + :: + =^ res acc + ?> ?=(^ a) + (f state.acc n.a) + :: apply update to .a from .f's product + :: + =. a + :: 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 + ^+ . + ?~ a . + =/ lef main(a l.a) + lef(a a(l a.lef)) + :: +right: recurse on right subtree, copying mutant back into .r.a + :: + ++ right + ^+ . + ?~ a . + =/ rig main(a r.a) + rig(a a(r a.rig)) + -- + :: +tap: convert to list, smallest to largest + :: + ++ tap + |= a=(tree item) + ^- (list item) + :: + =| b=(list item) + |- ^+ b + ?~ a b + :: + $(a l.a, b [n.a $(a r.a)]) + :: +gas: put a list of items + :: + ++ gas + |= [a=(tree item) b=(list item)] + ^- (tree item) + :: + ?~ b a + $(b t.b, a (put a i.b)) + :: +uni: unify two ordered maps + :: + :: .b takes precedence over .a if keys overlap. + :: + ++ uni + |= [a=(tree item) b=(tree item)] + ^- (tree item) + :: + ?~ b a + ?~ a b + ?: =(key.n.a key.n.b) + :: + [n=n.b l=$(a l.a, b l.b) r=$(a r.a, b r.b)] + :: + ?: (mor key.n.a key.n.b) + :: + ?: (compare key.n.b key.n.a) + $(l.a $(a l.a, r.b ~), b r.b) + $(r.a $(a r.a, l.b ~), b l.b) + :: + ?: (compare key.n.a key.n.b) + $(l.b $(b l.b, r.a ~), a r.a) + $(r.b $(b r.b, l.a ~), a l.a) + :: + :: +get: get val at key or return ~ + :: + ++ get + |= [a=(tree item) b=key] + ^- (unit val) + ?~ a ~ + ?: =(b key.n.a) + `val.n.a + ?: (compare b key.n.a) + $(a l.a) + $(a r.a) + :: + :: +subset: take a range excluding start and/or end and all elements + :: outside the range + :: + ++ subset + |= $: tre=(tree item) + start=(unit key) + end=(unit key) + == + ^- (tree item) + |^ + ?: ?&(?=(~ start) ?=(~ end)) + tre + ?~ start + (del-span tre %end end) + ?~ end + (del-span tre %start start) + ?> (lth u.start u.end) + =. tre (del-span tre %start start) + (del-span tre %end end) + :: + ++ del-span + |= [a=(tree item) b=?(%start %end) c=(unit key)] + ^- (tree item) + ?~ a a + ?~ c a + ?- b + %start + :: found key + ?: =(key.n.a u.c) + (nip a(l ~)) + :: traverse to find key + ?: (compare key.n.a u.c) + :: found key to the left of start + $(a (nip a(l ~))) + :: found key to the right of start + a(l $(a l.a)) + :: + %end + :: found key + ?: =(u.c key.n.a) + (nip a(r ~)) + :: traverse to find key + ?: (compare key.n.a u.c) + :: found key to the left of end + a(r $(a r.a)) + :: found key to the right of end + $(a (nip a(r ~))) + == + -- + -- +-- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index f1eccab029..e6b9a86e59 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -16,12 +16,12 @@ :: +$ graph ((mop atom node) lth) +$ internal-graph - $~ [%not-loaded ~] + $~ [%empty ~] $% :: :: a graph and timestamp of when it was last modified [%graph p=graph q=time] - [%empty-when-fetched p=time] - [%not-loaded ~] + [%empty ~] + [%empty-at-time p=time] == :: +$ node [=post children=internal-graph] From bc0c1e72454b389721a551d44918132173248efe Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 5 Jun 2020 16:31:55 -0400 Subject: [PATCH 005/543] graph-store: remove-nodes compiles --- pkg/arvo/app/graph-store.hoon | 66 +++++++++++++++++++++++++++++++++-- pkg/arvo/sur/graph-store.hoon | 2 +- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index be7615db7a..d9f1682141 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -144,9 +144,71 @@ -- :: ++ remove-nodes - |= uids=(set uid:store) + |= nodes=(jug resource:store index:store) ^- (quip card _state) - [~ state] + =/ resource-list=(list [resource:store (set index:store)]) + ~(tap by nodes) + |^ + ?~ resource-list + :_ state + (give [/all]~ [%remove-nodes nodes]) + =* resource -.i.resource-list + =/ graph=(unit graph:store) (~(get by graphs) resource) + ?~ graph + ~& "graph {} does not exist to add a node to!" + $(resource-list t.resource-list) + %_ $ + resource-list t.resource-list + graphs + %+ ~(put by graphs) + resource + (remove-indices resource u.graph ~(tap in +.i.resource-list)) + == + :: + ++ remove-indices + |= [=resource:store =graph:store indices=(list index:store)] + ^- graph:store + |- + ?~ indices graph + %_ $ + indices t.indices + graph (remove-index graph i.indices) + == + :: + ++ remove-index + |= [=graph:store =index:store] + ^- graph:store + ?~ index graph + =* atom i.index + :: last index in list + :: + ?~ t.index + =/ node-and-graph=[(unit node:store) graph:store] + (del:orm graph atom) + +.node-and-graph + :: multiple indices left in list + :: + =/ parent=(unit node:store) (get:orm graph atom) + ?~ parent + ~& "index does not exist to remove a node from!" + graph + =/ par=node:store (need parent) + ?+ -.children.par + ~& "child index does not exist to remove a node from!" + graph + :: + %graph + :: recurse into children + :: + %^ put:orm + graph + atom + %_ par + p.children $(graph p.children.par, index t.index) + q.children now.bowl + == + == + -- :: ++ add-signatures |= [=uid:store =signatures:store] diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index e6b9a86e59..b8561011f2 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -30,7 +30,7 @@ [%remove-graph =resource] :: [%add-nodes nodes=(map resource (map index node))] - [%remove-nodes uids=(set uid)] + [%remove-nodes nodes=(jug resource index)] :: [%add-signatures =uid =signatures] [%remove-signatures =uid =signatures] From f8d860c0ef16d7278c39aeee44b8e15a5cf8eab2 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Mon, 8 Jun 2020 17:44:51 -0400 Subject: [PATCH 006/543] graph-store: added %add-signatures, action-log, stubbed signature verification --- pkg/arvo/app/graph-store.hoon | 193 +++++++++++++++++++++------------- pkg/arvo/lib/signatures.hoon | 38 +++++++ pkg/arvo/sur/graph-store.hoon | 37 ++++--- pkg/arvo/sur/post.hoon | 8 +- 4 files changed, 187 insertions(+), 89 deletions(-) create mode 100644 pkg/arvo/lib/signatures.hoon diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index d9f1682141..f054a830eb 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -1,12 +1,12 @@ -/+ store=graph-store, *or-map, default-agent, dbug +/+ store=graph-store, sigs=signatures, *or-map, default-agent, dbug |% +$ card card:agent:gall +$ versioned-state $% state-0 == +$ state-0 [%0 network:store] -:: -++ orm ((or-map atom:store node:store) lth) +++ orm ((or-map atom:store node:store) lth) +++ orm-log ((or-map time action:store) lth) -- :: =| state-0 @@ -41,15 +41,16 @@ |= =action:store ^- (quip card _state) |^ - ?- -.action - %add-graph (add-graph +.action) - %remove-graph (remove-graph +.action) - %add-nodes (add-nodes +.action) - %remove-nodes (remove-nodes +.action) - %add-signatures (add-signatures +.action) - %remove-signatures (remove-signatures +.action) - %add-tag (add-tag +.action) - %remove-tag (remove-tag +.action) + ?> ?=(%0 -.action) + ?- +<.action + %add-graph (add-graph +>.action) + %remove-graph (remove-graph +>.action) + %add-nodes (add-nodes +>.action) + %remove-nodes (remove-nodes +>.action) + %add-signatures (add-signatures +>.action) + %remove-signatures (remove-signatures +>.action) + %add-tag (add-tag +>.action) + %remove-tag (remove-tag +>.action) == :: ++ add-graph @@ -57,35 +58,37 @@ ^- (quip card _state) ?< (~(has by graphs) resource) :- (give [/all /keys ~] [%add-graph resource graph]) - state(graphs (~(put by graphs) resource graph)) + %= state + graphs (~(put by graphs) resource graph) + action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) + == :: ++ remove-graph |= =resource:store ^- (quip card _state) ?> (~(has by graphs) resource) :- (give [/all /keys ~] [%remove-graph resource]) - state(graphs (~(del by graphs) resource)) + %= state + graphs (~(del by graphs) resource) + action-logs (~(del by action-logs) resource) + == :: ++ add-nodes - |= nodes=(map resource:store (map index:store node:store)) + |= [=resource:store nodes=(map index:store node:store)] ^- (quip card _state) - =/ resource-list ~(tap by nodes) |^ - ?~ resource-list - :_ state - (give [/all]~ [%add-nodes nodes]) - =* resource -.i.resource-list - =/ indexed-nodes=(map index:store node:store) +.i.resource-list - =/ graph=(unit graph:store) (~(get by graphs) resource) - ?~ graph - ~& "graph {} does not exist to add a node to!" - $(resource-list t.resource-list) - %_ $ - resource-list t.resource-list + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + (put:orm-log action-log now.bowl [%0 [%add-nodes resource nodes]]) + :: + :- (give [/all]~ [%add-nodes resource nodes]) + %_ state + action-logs (~(put by action-logs) resource action-log) graphs %+ ~(put by graphs) resource - (add-node-list resource u.graph ~(tap by indexed-nodes)) + (add-node-list resource graph ~(tap by nodes)) == :: ++ add-node-list @@ -94,7 +97,6 @@ node-list=(list [index:store node:store]) == ^- graph:store - |- ?~ node-list graph =* index -.i.node-list =* node +.i.node-list @@ -110,24 +112,25 @@ =* atom i.index :: last index in list :: - ?~ t.index (put:orm graph atom node) + ?~ t.index + :: TODO: validate that hash of node matches + (put:orm graph atom node) :: multiple indices left in list :: =/ parent=(unit node:store) (get:orm graph atom) ?~ parent ~& "index does not exist to add a node to!" graph - =/ par=node:store (need parent) - ?+ -.children.par + ?+ -.children.u.parent :: replace empty graph with graph containing one child :: %^ put:orm graph atom - %= par + %= u.parent children ^- internal-graph:store - [%graph $(graph (gas:orm ~ ~), index t.index) now.bowl] + [%graph $(graph (gas:orm ~ ~), index t.index)] == :: %graph @@ -136,39 +139,33 @@ %^ put:orm graph atom - %_ par - p.children $(graph p.children.par, index t.index) - q.children now.bowl + %_ u.parent + p.children $(graph p.children.u.parent, index t.index) == == -- :: ++ remove-nodes - |= nodes=(jug resource:store index:store) + |= [=resource:store indices=(set index:store)] ^- (quip card _state) - =/ resource-list=(list [resource:store (set index:store)]) - ~(tap by nodes) |^ - ?~ resource-list - :_ state - (give [/all]~ [%remove-nodes nodes]) - =* resource -.i.resource-list - =/ graph=(unit graph:store) (~(get by graphs) resource) - ?~ graph - ~& "graph {} does not exist to add a node to!" - $(resource-list t.resource-list) - %_ $ - resource-list t.resource-list + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + (put:orm-log action-log now.bowl [%0 [%remove-nodes resource indices]]) + :: + :- (give [/all]~ [%remove-nodes resource indices]) + %_ state + action-logs (~(put by action-logs) resource action-log) graphs %+ ~(put by graphs) resource - (remove-indices resource u.graph ~(tap in +.i.resource-list)) + (remove-indices resource graph ~(tap in indices)) == :: ++ remove-indices |= [=resource:store =graph:store indices=(list index:store)] ^- graph:store - |- ?~ indices graph %_ $ indices t.indices @@ -183,17 +180,14 @@ :: last index in list :: ?~ t.index - =/ node-and-graph=[(unit node:store) graph:store] - (del:orm graph atom) - +.node-and-graph + +:`[* graph:store]`(del:orm graph atom) :: multiple indices left in list :: =/ parent=(unit node:store) (get:orm graph atom) ?~ parent ~& "index does not exist to remove a node from!" graph - =/ par=node:store (need parent) - ?+ -.children.par + ?+ -.children.u.parent ~& "child index does not exist to remove a node from!" graph :: @@ -203,9 +197,8 @@ %^ put:orm graph atom - %_ par - p.children $(graph p.children.par, index t.index) - q.children now.bowl + %_ u.parent + p.children $(graph p.children.u.parent, index t.index) == == -- @@ -213,7 +206,58 @@ ++ add-signatures |= [=uid:store =signatures:store] ^- (quip card _state) - [~ state] + |^ + =* resource resource.uid + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + (put:orm-log action-log now.bowl [%0 [%add-signatures uid signatures]]) + :: + :- (give [/all]~ [%add-signatures uid signatures]) + %_ state + action-logs (~(put by action-logs) resource action-log) + graphs + (~(put by graphs) resource (add-at-index graph index.uid signatures)) + == + :: + ++ add-at-index + |= [=graph:store =index:store =signatures:store] + ^- graph:store + ?~ index graph + =* atom i.index + =/ node=(unit node:store) (get:orm graph atom) + ?~ node + ~|("node does not exist to add signatures to!" !!) + :: last index in list + :: + ?~ t.index + :: TODO: finish this + ?. (are-signatures-valid:sigs signatures *hash:store now.bowl) + ~|("signatures did not match public keys!" !!) + =/ new-signatures (~(uni in signatures) p.signatures.post.u.node) + %^ put:orm + graph + atom + %_ u.node + p.signatures.post new-signatures + q.signatures.post (sha256-mug:sigs new-signatures) + == + :: multiple indices left in list + :: + ?+ -.children.u.node + ~|("child graph does not exist to add signatures to!" !!) + :: + %graph + :: recurse into children + :: + %^ put:orm + graph + atom + %_ u.node + p.children $(graph p.children.u.node, index t.index) + == + == + -- :: ++ remove-signatures |= [=uid:store =signatures:store] @@ -221,20 +265,27 @@ [~ state] :: ++ add-tag - |= [=term =resources:store] + |= [=term =resource:store] ^- (quip card _state) - [~ state] + ?> (~(has by graphs) resource) + :- (give [/all]~ [%add-tag term resource]) + %_ state + tag-queries (~(put ju tag-queries) term resource) + == :: ++ remove-tag - |= [=term =resources:store] + |= [=term =resource:store] ^- (quip card _state) - [~ state] - :: + ?> (~(has by graphs) resource) + :- (give [/all]~ [%remove-tag term resource]) + %_ state + tag-queries (~(del ju tag-queries) term resource) + == :: ++ give - |= [paths=(list path) =update:store] + |= [paths=(list path) update=update-0:store] ^- (list card) - [%give %fact paths [%graph-update !>(update)]]~ + [%give %fact paths [%graph-update !>([%0 update])]]~ -- -- :: @@ -245,15 +296,15 @@ ?> (team:title our.bowl src.bowl) =/ cards=(list card) ?+ path (on-watch:def path) - [%all ~] (give [%initial graphs tags tag-queries]) + [%all ~] (give [%initial graphs tag-queries]) [%keys ~] (give [%keys ~(key by graphs)]) == [cards this] :: ++ give - |= =update:store + |= update=update-0:store ^- (list card) - [%give %fact ~ [%graph-update !>(update)]]~ + [%give %fact ~ [%graph-update !>([%0 update])]]~ -- :: ++ on-peek diff --git a/pkg/arvo/lib/signatures.hoon b/pkg/arvo/lib/signatures.hoon new file mode 100644 index 0000000000..fc0a944ebf --- /dev/null +++ b/pkg/arvo/lib/signatures.hoon @@ -0,0 +1,38 @@ +/- post +^? +=< [post .] +=, post +|% +:: +:: sha256 noun hash +:: +++ sha256-mug + |= yux/* ^- @ux ^- @ + ?@ yux + (shax yux) + (shax (jam yux)) +:: +++ is-signature-valid + |= [=signature =hash now=time] + ^- ? + =/ =pass + .^ pass + %j + /=deed/(scot %da now)/(scot %p q.signature)/(scot %ud p.signature) + == + :: verify signature against hash of post + ?: %.y + %.n + %.y +:: +++ are-signatures-valid + |= [=signatures =hash now=time] + ^- ? + =/ signature-list ~(tap in signatures) + |- + ?~ signature-list + %.y + ?: (is-signature-valid i.signature-list hash now) + $(signature-list t.signature-list) + %.n +-- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index b8561011f2..5b5492c736 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -8,40 +8,51 @@ ?> (check-balance:((ordered-map key value) ord) b) b :: ++$ graphs (map resource graph) ++$ tag-queries (jug term resource) ++$ action-logs (map resource action-log) +$ network - $: graphs=(map resource graph) - tags=(set term) - tag-queries=(map term resources) + $: =graphs + =tag-queries + =action-logs == :: ++$ action-log ((mop time action) lth) +:: +$ graph ((mop atom node) lth) +$ internal-graph $~ [%empty ~] - $% :: - :: a graph and timestamp of when it was last modified - [%graph p=graph q=time] + $% [%graph p=graph] [%empty ~] - [%empty-at-time p=time] == :: +$ node [=post children=internal-graph] +:: +$ action + $% [%0 action-0] + == +:: ++$ action-0 $% [%add-graph =resource =graph] [%remove-graph =resource] :: - [%add-nodes nodes=(map resource (map index node))] - [%remove-nodes nodes=(jug resource index)] + [%add-nodes =resource nodes=(map index node)] + [%remove-nodes =resource indices=(set index)] :: [%add-signatures =uid =signatures] [%remove-signatures =uid =signatures] :: - [%add-tag =term =resources] - [%remove-tag =term =resources] + [%add-tag =term =resource] + [%remove-tag =term =resource] == :: +$ update + $% [%0 update-0] + == +:: ++$ update-0 $% [%keys =resources] - [%initial =network] - action + [%initial =graphs =tag-queries] + action-0 == -- diff --git a/pkg/arvo/sur/post.hoon b/pkg/arvo/sur/post.hoon index f187c3d465..120360675d 100644 --- a/pkg/arvo/sur/post.hoon +++ b/pkg/arvo/sur/post.hoon @@ -4,12 +4,10 @@ +$ index (list atom) +$ uid [=resource =index] :: -+$ hash - $% [%sha256 p=@ux] - [%murmur3 p=@ux] - == +:: must be sha256 hash ++$ hash @ux :: -+$ signature @ux ++$ signature [p=@ux q=ship r=life] +$ signatures (set signature) +$ post $: author=ship From d44e7eb9caa809c314db8d04854c4a673d46252d Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 9 Jun 2020 14:48:05 -0400 Subject: [PATCH 007/543] graph-store: first pass at signing, hashing, and verifying nodes --- pkg/arvo/app/graph-store.hoon | 55 ++++++++++++++++++++++++++--------- pkg/arvo/lib/signatures.hoon | 17 +++++++---- pkg/arvo/sur/post.hoon | 16 +++++++--- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index f054a830eb..117ebec82d 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -58,7 +58,7 @@ ^- (quip card _state) ?< (~(has by graphs) resource) :- (give [/all /keys ~] [%add-graph resource graph]) - %= state + %_ state graphs (~(put by graphs) resource graph) action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) == @@ -68,7 +68,7 @@ ^- (quip card _state) ?> (~(has by graphs) resource) :- (give [/all /keys ~] [%remove-graph resource]) - %= state + %_ state graphs (~(del by graphs) resource) action-logs (~(del by action-logs) resource) == @@ -102,19 +102,47 @@ =* node +.i.node-list %_ $ node-list t.node-list - graph (add-node-at-index graph index node) + graph (add-node-at-index graph index node ~) == :: ++ add-node-at-index - |= [=graph:store =index:store =node:store] + |= $: =graph:store + =index:store + =node:store + parent-hash=(unit hash:store) + == ^- graph:store ?~ index graph =* atom i.index :: last index in list :: ?~ t.index - :: TODO: validate that hash of node matches - (put:orm graph atom node) + :: verify hash if it exists, otherwise calculate + :: + =* p post.node + =/ =validated-portion:store + [parent-hash author.p index.p time-sent.p contents.p] + =/ calculated-hash (mug validated-portion) + ?^ hash.p + :: hash is present, validate it + ~| "hash of post does not match calculated hash" + ?> =(calculated-hash u.hash.p) + (put:orm graph atom node) + :: no hash present + :: + %^ put:orm + graph + atom + %= node + hash.post `calculated-hash + signatures.post + ?. =(our.bowl author.post.node) ~ + %- ~(gas in *signatures:store) + :_ ~ + :+ `@ux`(sign:as:crub:crypto calculated-hash) + our.bowl + .^(=life %j /=life/(scot %p our.bowl)) + == :: multiple indices left in list :: =/ parent=(unit node:store) (get:orm graph atom) @@ -124,23 +152,27 @@ ?+ -.children.u.parent :: replace empty graph with graph containing one child :: + =* p-hash hash.post.u.parent %^ put:orm graph atom %= u.parent children ^- internal-graph:store - [%graph $(graph (gas:orm ~ ~), index t.index)] + :- %graph + $(graph (gas:orm ~ ~), index t.index, parent-hash p-hash) == :: %graph :: recurse into children :: + =* p-hash hash.post.u.parent %^ put:orm graph atom %_ u.parent - p.children $(graph p.children.u.parent, index t.index) + p.children + $(graph p.children.u.parent, index t.index, parent-hash p-hash) == == -- @@ -234,14 +266,11 @@ :: TODO: finish this ?. (are-signatures-valid:sigs signatures *hash:store now.bowl) ~|("signatures did not match public keys!" !!) - =/ new-signatures (~(uni in signatures) p.signatures.post.u.node) + =/ new-signatures (~(uni in signatures) signatures.post.u.node) %^ put:orm graph atom - %_ u.node - p.signatures.post new-signatures - q.signatures.post (sha256-mug:sigs new-signatures) - == + u.node(signatures.post new-signatures) :: multiple indices left in list :: ?+ -.children.u.node diff --git a/pkg/arvo/lib/signatures.hoon b/pkg/arvo/lib/signatures.hoon index fc0a944ebf..060f207ab8 100644 --- a/pkg/arvo/lib/signatures.hoon +++ b/pkg/arvo/lib/signatures.hoon @@ -15,15 +15,20 @@ ++ is-signature-valid |= [=signature =hash now=time] ^- ? - =/ =pass - .^ pass + =/ deed=(unit [a=life b=pass c=(unit @ux)]) + .^ (unit [life pass (unit @ux)]) %j /=deed/(scot %da now)/(scot %p q.signature)/(scot %ud p.signature) == - :: verify signature against hash of post - ?: %.y - %.n - %.y + :: we do not have a public key from ship + :: + ?~ deed %.y + :: we do not have a public key from ship at this life + :: + ?. =(a.u.deed r.signature) %.y + :: verify signature from ship at life + :: + ?=(^ (tear:as:crub:crypto b.u.deed p.signature)) :: ++ are-signatures-valid |= [=signatures =hash now=time] diff --git a/pkg/arvo/sur/post.hoon b/pkg/arvo/sur/post.hoon index 120360675d..20b0bd6d67 100644 --- a/pkg/arvo/sur/post.hoon +++ b/pkg/arvo/sur/post.hoon @@ -4,18 +4,26 @@ +$ index (list atom) +$ uid [=resource =index] :: -:: must be sha256 hash +:: mug hash of +validated-portion +$ hash @ux :: +$ signature [p=@ux q=ship r=life] +$ signatures (set signature) +$ post $: author=ship - =hash =index - contents=(list content) - signatures=[p=signatures q=hash] time-sent=time + contents=(list content) + hash=(unit hash) + =signatures + == +:: ++$ validated-portion + $: parent-hash=(unit hash) + author=ship + =index + time-sent=time + contents=(list content) == :: +$ content From 3ce10fe01e3f0a928f27a2061a7da46fa2d226f0 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Wed, 10 Jun 2020 12:08:49 -0400 Subject: [PATCH 008/543] graph-store: finished first draft of all actions --- pkg/arvo/app/graph-store.hoon | 172 ++++++++++++++++++---------------- 1 file changed, 91 insertions(+), 81 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 117ebec82d..354f57c925 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -57,7 +57,7 @@ |= [=resource:store =graph:store] ^- (quip card _state) ?< (~(has by graphs) resource) - :- (give [/all /keys ~] [%add-graph resource graph]) + :- (give [/updates /keys ~] [%add-graph resource graph]) %_ state graphs (~(put by graphs) resource graph) action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) @@ -67,7 +67,7 @@ |= =resource:store ^- (quip card _state) ?> (~(has by graphs) resource) - :- (give [/all /keys ~] [%remove-graph resource]) + :- (give [/updates /keys ~] [%remove-graph resource]) %_ state graphs (~(del by graphs) resource) action-logs (~(del by action-logs) resource) @@ -82,7 +82,7 @@ =. action-log (put:orm-log action-log now.bowl [%0 [%add-nodes resource nodes]]) :: - :- (give [/all]~ [%add-nodes resource nodes]) + :- (give [/updates]~ [%add-nodes resource nodes]) %_ state action-logs (~(put by action-logs) resource action-log) graphs @@ -116,6 +116,9 @@ =* atom i.index :: last index in list :: + %^ put:orm + graph + atom ?~ t.index :: verify hash if it exists, otherwise calculate :: @@ -127,12 +130,9 @@ :: hash is present, validate it ~| "hash of post does not match calculated hash" ?> =(calculated-hash u.hash.p) - (put:orm graph atom node) + node :: no hash present :: - %^ put:orm - graph - atom %= node hash.post `calculated-hash signatures.post @@ -145,34 +145,23 @@ == :: multiple indices left in list :: - =/ parent=(unit node:store) (get:orm graph atom) - ?~ parent - ~& "index does not exist to add a node to!" - graph - ?+ -.children.u.parent - :: replace empty graph with graph containing one child - :: - =* p-hash hash.post.u.parent - %^ put:orm + ~| "index does not exist to add a node to!" + =/ parent=node:store (need (get:orm graph atom)) + %_ parent + children + ^- internal-graph:store + :- %graph + %_ $ + index t.index + parent-hash hash.post.parent graph - atom - %= u.parent - children - ^- internal-graph:store - :- %graph - $(graph (gas:orm ~ ~), index t.index, parent-hash p-hash) - == - :: - %graph - :: recurse into children - :: - =* p-hash hash.post.u.parent - %^ put:orm - graph - atom - %_ u.parent - p.children - $(graph p.children.u.parent, index t.index, parent-hash p-hash) + ?: ?=(%graph -.children.parent) + :: recurse into children + :: + p.children.parent + :: replace empty graph with graph containing one child + :: + (gas:orm ~ ~) == == -- @@ -186,7 +175,7 @@ =. action-log (put:orm-log action-log now.bowl [%0 [%remove-nodes resource indices]]) :: - :- (give [/all]~ [%remove-nodes resource indices]) + :- (give [/updates]~ [%remove-nodes resource indices]) %_ state action-logs (~(put by action-logs) resource action-log) graphs @@ -215,24 +204,16 @@ +:`[* graph:store]`(del:orm graph atom) :: multiple indices left in list :: - =/ parent=(unit node:store) (get:orm graph atom) - ?~ parent - ~& "index does not exist to remove a node from!" - graph - ?+ -.children.u.parent - ~& "child index does not exist to remove a node from!" - graph + ~| "parent index does not exist to remove a node from!" + =/ =node:store (need (get:orm graph atom)) + ~| "child index does not exist to remove a node from!" + ?> ?=(%graph -.children.node) + :: recurse into children :: - %graph - :: recurse into children - :: - %^ put:orm - graph - atom - %_ u.parent - p.children $(graph p.children.u.parent, index t.index) - == - == + %^ put:orm + graph + atom + node(p.children $(graph p.children.node, index t.index)) -- :: ++ add-signatures @@ -245,7 +226,7 @@ =. action-log (put:orm-log action-log now.bowl [%0 [%add-signatures uid signatures]]) :: - :- (give [/all]~ [%add-signatures uid signatures]) + :- (give [/updates]~ [%add-signatures uid signatures]) %_ state action-logs (~(put by action-logs) resource action-log) graphs @@ -257,47 +238,76 @@ ^- graph:store ?~ index graph =* atom i.index - =/ node=(unit node:store) (get:orm graph atom) - ?~ node - ~|("node does not exist to add signatures to!" !!) + ~| "node does not exist to add signatures to!" + =/ =node:store (need (get:orm graph atom)) :: last index in list :: + %^ put:orm + graph + atom ?~ t.index - :: TODO: finish this - ?. (are-signatures-valid:sigs signatures *hash:store now.bowl) - ~|("signatures did not match public keys!" !!) - =/ new-signatures (~(uni in signatures) signatures.post.u.node) - %^ put:orm - graph - atom - u.node(signatures.post new-signatures) + ~| "cannot add signatures to a node missing a hash" + ?> ?=(^ hash.post.node) + ~| "signatures did not match public keys!" + ?> (are-signatures-valid:sigs signatures u.hash.post.node now.bowl) + node(signatures.post (~(uni in signatures) signatures.post.node)) :: multiple indices left in list :: - ?+ -.children.u.node - ~|("child graph does not exist to add signatures to!" !!) + ~| "child graph does not exist to add signatures to!" + ?> ?=(%graph -.children.node) + :: recurse into children :: - %graph - :: recurse into children - :: - %^ put:orm - graph - atom - %_ u.node - p.children $(graph p.children.u.node, index t.index) - == - == + node(p.children $(graph p.children.node, index t.index)) -- :: ++ remove-signatures |= [=uid:store =signatures:store] ^- (quip card _state) - [~ state] + |^ + =* resource resource.uid + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + %^ put:orm-log action-log + now.bowl + [%0 [%remove-signatures uid signatures]] + :: + :- (give [/updates]~ [%remove-signatures uid signatures]) + %_ state + action-logs (~(put by action-logs) resource action-log) + graphs + %+ ~(put by graphs) resource + (remove-at-index graph index.uid signatures) + == + :: + ++ remove-at-index + |= [=graph:store =index:store =signatures:store] + ^- graph:store + ?~ index graph + =* atom i.index + ~| "node does not exist to add signatures to!" + =/ =node:store (need (get:orm graph atom)) + :: last index in list + :: + %^ put:orm + graph + atom + ?~ t.index + node(signatures.post (~(dif in signatures) signatures.post.node)) + :: multiple indices left in list + :: + ~| "child graph does not exist to add signatures to!" + ?> ?=(%graph -.children.node) + :: recurse into children + :: + node(p.children $(graph p.children.node, index t.index)) + -- :: ++ add-tag |= [=term =resource:store] ^- (quip card _state) ?> (~(has by graphs) resource) - :- (give [/all]~ [%add-tag term resource]) + :- (give [/updates]~ [%add-tag term resource]) %_ state tag-queries (~(put ju tag-queries) term resource) == @@ -306,7 +316,7 @@ |= [=term =resource:store] ^- (quip card _state) ?> (~(has by graphs) resource) - :- (give [/all]~ [%remove-tag term resource]) + :- (give [/updates]~ [%remove-tag term resource]) %_ state tag-queries (~(del ju tag-queries) term resource) == @@ -325,8 +335,8 @@ ?> (team:title our.bowl src.bowl) =/ cards=(list card) ?+ path (on-watch:def path) - [%all ~] (give [%initial graphs tag-queries]) - [%keys ~] (give [%keys ~(key by graphs)]) + [%updates ~] ~ + [%keys ~] (give [%keys ~(key by graphs)]) == [cards this] :: From c9ccbdabefc2a32c7a61c1e8dcd5735df2443263 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Wed, 10 Jun 2020 12:17:55 -0400 Subject: [PATCH 009/543] graph-store: added action generators --- pkg/arvo/app/graph-store.hoon | 1 - pkg/arvo/gen/graph-store/add-graph.hoon | 10 ++++++++++ pkg/arvo/gen/graph-store/add-nodes.hoon | 10 ++++++++++ pkg/arvo/gen/graph-store/add-signatures.hoon | 10 ++++++++++ pkg/arvo/gen/graph-store/add-tag.hoon | 10 ++++++++++ pkg/arvo/gen/graph-store/remove-graph.hoon | 10 ++++++++++ pkg/arvo/gen/graph-store/remove-nodes.hoon | 10 ++++++++++ pkg/arvo/gen/graph-store/remove-signatures.hoon | 11 +++++++++++ pkg/arvo/gen/graph-store/remove-tag.hoon | 10 ++++++++++ pkg/arvo/lib/graph-store.hoon | 14 ++++++++++++++ 10 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 pkg/arvo/gen/graph-store/add-graph.hoon create mode 100644 pkg/arvo/gen/graph-store/add-nodes.hoon create mode 100644 pkg/arvo/gen/graph-store/add-signatures.hoon create mode 100644 pkg/arvo/gen/graph-store/add-tag.hoon create mode 100644 pkg/arvo/gen/graph-store/remove-graph.hoon create mode 100644 pkg/arvo/gen/graph-store/remove-nodes.hoon create mode 100644 pkg/arvo/gen/graph-store/remove-signatures.hoon create mode 100644 pkg/arvo/gen/graph-store/remove-tag.hoon diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 354f57c925..1f139410cb 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -23,7 +23,6 @@ ++ on-load |= old=vase ^- (quip card _this) - ::[~ this] [~ this(state !<(state-0 old))] :: ++ on-poke diff --git a/pkg/arvo/gen/graph-store/add-graph.hoon b/pkg/arvo/gen/graph-store/add-graph.hoon new file mode 100644 index 0000000000..18bb388c48 --- /dev/null +++ b/pkg/arvo/gen/graph-store/add-graph.hoon @@ -0,0 +1,10 @@ +:: graph-store|add-graph: add new graph +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=resource =graph ~] ~] + == +:- %graph-action +^- action +[%0 [%add-graph resource graph]] diff --git a/pkg/arvo/gen/graph-store/add-nodes.hoon b/pkg/arvo/gen/graph-store/add-nodes.hoon new file mode 100644 index 0000000000..3e60b4249f --- /dev/null +++ b/pkg/arvo/gen/graph-store/add-nodes.hoon @@ -0,0 +1,10 @@ +:: graph-store|add-nodes: add nodes to a graph at a particular resource +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=resource nodes=(map index node) ~] ~] + == +:- %graph-action +^- action +[%0 [%add-nodes resource nodes]] diff --git a/pkg/arvo/gen/graph-store/add-signatures.hoon b/pkg/arvo/gen/graph-store/add-signatures.hoon new file mode 100644 index 0000000000..c28fb3da08 --- /dev/null +++ b/pkg/arvo/gen/graph-store/add-signatures.hoon @@ -0,0 +1,10 @@ +:: graph-store|add-signatures: add signatures to a node at a particular uid +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=uid =signatures ~] ~] + == +:- %graph-action +^- action +[%0 [%add-signatures uid signatures]] diff --git a/pkg/arvo/gen/graph-store/add-tag.hoon b/pkg/arvo/gen/graph-store/add-tag.hoon new file mode 100644 index 0000000000..20487ea806 --- /dev/null +++ b/pkg/arvo/gen/graph-store/add-tag.hoon @@ -0,0 +1,10 @@ +:: graph-store|add-tag: tag a particular graph +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=term =resource ~] ~] + == +:- %graph-action +^- action +[%0 [%add-tag term resource]] diff --git a/pkg/arvo/gen/graph-store/remove-graph.hoon b/pkg/arvo/gen/graph-store/remove-graph.hoon new file mode 100644 index 0000000000..cd66f1d7c1 --- /dev/null +++ b/pkg/arvo/gen/graph-store/remove-graph.hoon @@ -0,0 +1,10 @@ +:: graph-store|remove-graph: remove graph +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=resource ~] ~] + == +:- %graph-action +^- action +[%0 [%remove-graph resource]] diff --git a/pkg/arvo/gen/graph-store/remove-nodes.hoon b/pkg/arvo/gen/graph-store/remove-nodes.hoon new file mode 100644 index 0000000000..27b97b3ab0 --- /dev/null +++ b/pkg/arvo/gen/graph-store/remove-nodes.hoon @@ -0,0 +1,10 @@ +:: graph-store|remove-nodes: remove nodes from a graph at indices +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=resource indices=(set index) ~] ~] + == +:- %graph-action +^- action +[%0 [%remove-nodes resource indices]] diff --git a/pkg/arvo/gen/graph-store/remove-signatures.hoon b/pkg/arvo/gen/graph-store/remove-signatures.hoon new file mode 100644 index 0000000000..fb58baa46d --- /dev/null +++ b/pkg/arvo/gen/graph-store/remove-signatures.hoon @@ -0,0 +1,11 @@ +:: graph-store|remove-signatures: remove signatures from a node at a +:: particular uid +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=uid =signatures ~] ~] + == +:- %graph-action +^- action +[%0 [%remove-signatures uid signatures]] diff --git a/pkg/arvo/gen/graph-store/remove-tag.hoon b/pkg/arvo/gen/graph-store/remove-tag.hoon new file mode 100644 index 0000000000..736e7c6dd5 --- /dev/null +++ b/pkg/arvo/gen/graph-store/remove-tag.hoon @@ -0,0 +1,10 @@ +:: graph-store|remove-tag: remove a tag from a particular graph +:: +/- *graph-store +:- %say +|= $: [now=@da eny=@uvJ =beak] + [[=term =resource ~] ~] + == +:- %graph-action +^- action +[%0 [%remove-tag term resource]] diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 7a3f69ea27..8751300caf 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -30,4 +30,18 @@ ^- ^action !! -- +:: +++ create + |_ [our=ship now=time] + ++ post + |= [=index contents=(list content)] + ^- ^post + :* our + index + now + contents + ~ + *signatures + == + -- -- From 81deb6247f1173e1477de68a171f78da125e5e84 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Wed, 10 Jun 2020 14:45:00 -0400 Subject: [PATCH 010/543] graph-store: stubbed out json encoding --- pkg/arvo/lib/graph-store.hoon | 97 ++++++++++++++++++++++++++++++++--- pkg/arvo/lib/resource.hoon | 46 +++++++++++++++++ pkg/arvo/sur/graph-store.hoon | 1 - pkg/arvo/sur/resource.hoon | 6 +-- 4 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 pkg/arvo/lib/resource.hoon diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 8751300caf..c403468cc1 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -1,11 +1,10 @@ -/- sur=graph-store, pos=post, res=resource -^? +/- sur=graph-store, pos=post +/+ res=resource =< [sur .] =< [pos .] =< [res .] =, sur =, pos -=, res |% ++ enjs =, enjs:format @@ -13,12 +12,98 @@ ++ update |= upd=^update ^- json - |^ (frond %graph-update (pairs ~[(encode upd)])) + ?> ?=(%0 -.upd) + |^ (frond %graph-update (pairs ~[(encode +.upd)])) :: ++ encode - |= upd=^update + |= upd=update-0 ^- [cord json] - [*cord *json] + ?- -.upd + %keys + [%keys [%a (turn ~(tap in resources.upd) enjs:res)]] + :: + %add-graph + :- %add-graph + %- pairs + :~ [%resource (enjs:res resource.upd)] + [%graph (graph graph.upd)] + == + :: + %remove-graph + [%remove-graph (enjs:res resource.upd)] + :: + %add-nodes + :- %add-nodes + %- pairs + :~ [%resource (enjs:res resource.upd)] + [%nodes (nodes nodes.upd)] + == + :: + %remove-nodes + :- %remove-nodes + %- pairs + :~ [%resource (enjs:res resource.upd)] + [%indices (indices indices.upd)] + == + :: + %add-signatures + :- %add-signatures + %- pairs + :~ [%uid (uid uid.upd)] + [%signatures (signatures signatures.upd)] + == + :: + %remove-signatures + :- %remove-signatures + %- pairs + :~ [%uid (uid uid.upd)] + [%signatures (signatures signatures.upd)] + == + :: + %add-tag + :- %add-tag + %- pairs + :~ [%term s+term.upd] + [%resource (enjs:res resource.upd)] + == + :: + %remove-tag + :- %remove-tag + %- pairs + :~ [%term s+term.upd] + [%resource (enjs:res resource.upd)] + == + == + :: + ++ graph + |= g=^graph + ^- json + *json + :: + ++ index + |= i=^index + ^- json + *json + :: + ++ nodes + |= n=(map ^index node) + ^- json + *json + :: + ++ indices + |= i=(set ^index) + ^- json + *json + :: + ++ uid + |= u=^uid + ^- json + *json + :: + ++ signatures + |= s=^signatures + ^- json + *json -- -- :: diff --git a/pkg/arvo/lib/resource.hoon b/pkg/arvo/lib/resource.hoon new file mode 100644 index 0000000000..500fba88fa --- /dev/null +++ b/pkg/arvo/lib/resource.hoon @@ -0,0 +1,46 @@ +/- sur=resource +=< resource +|% ++$ resource resource:sur +++ en-path + |= =resource + ^- path + ~[%ship (scot %p entity.resource) name.resource] +:: +++ de-path + |= =path + ^- resource + (need (de-path-soft path)) +:: +++ de-path-soft + |= =path + ^- (unit resource) + ?. ?=([%ship @ @ *] path) + ~ + =/ ship + (slaw %p i.t.path) + ?~ ship + ~ + `[u.ship i.t.t.path] +:: +++ enjs + |= =resource + ^- json + =, enjs:format + %- pairs + :~ ship+(ship entity.resource) + name+s+name.resource + == +:: +++ enjs-path + |= =resource + %- spat + (en-path resource) +:: +++ dejs + =, dejs:format + %- ot + :~ ship+(su ;~(pfix sig fed:ag)) + name+so + == +-- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index 5b5492c736..5170d8e481 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -52,7 +52,6 @@ :: +$ update-0 $% [%keys =resources] - [%initial =graphs =tag-queries] action-0 == -- diff --git a/pkg/arvo/sur/resource.hoon b/pkg/arvo/sur/resource.hoon index b0b57e8217..eb74a37ec5 100644 --- a/pkg/arvo/sur/resource.hoon +++ b/pkg/arvo/sur/resource.hoon @@ -1,11 +1,9 @@ |% -+$ resource [=entity =term] ++$ resource [=entity name=term] +$ resources (set resource) :: +$ entity $@ ship - $% [%empty ~] - :: [%ships ships=(set ship)] - :: [%ring ...] + $% !! == -- From 31a6ec5d1c839bdf879485cda2d77e38f2c2d901 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Wed, 10 Jun 2020 16:47:18 -0400 Subject: [PATCH 011/543] graph-store: finished json encoding --- pkg/arvo/app/graph-store.hoon | 4 +- pkg/arvo/lib/graph-store.hoon | 101 +++++++++++++++++++++++++++++++--- pkg/arvo/sur/post.hoon | 4 +- 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 1f139410cb..b287f8f5f2 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -5,8 +5,8 @@ $% state-0 == +$ state-0 [%0 network:store] -++ orm ((or-map atom:store node:store) lth) -++ orm-log ((or-map time action:store) lth) +++ orm orm:store +++ orm-log orm-log:store -- :: =| state-0 diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index c403468cc1..fdbe6dcf81 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -1,11 +1,14 @@ /- sur=graph-store, pos=post -/+ res=resource +/+ res=resource, *or-map =< [sur .] =< [pos .] =< [res .] =, sur =, pos |% +++ orm ((or-map atom node) lth) +++ orm-log ((or-map time action) lth) +:: ++ enjs =, enjs:format |% @@ -78,32 +81,114 @@ ++ graph |= g=^graph ^- json - *json + :- %a + %+ turn (tap:orm g) + |= [a=atom n=^node] + ^- json + %- pairs + :~ [%key (numb a)] + [%node (node n)] + == :: ++ index |= i=^index ^- json - *json + =/ j=^tape "" + |- + ?~ i + [%s (crip j)] + =/ k=json (numb i.i) + ?> ?=(%n -.k) + %_ $ + i t.i + j (weld j (weld "/" (trip +.k))) + == + :: + ++ node + |= n=^node + ^- json + %- pairs + :~ [%post (post post.n)] + :- %children + ?- -.children.n + %empty ~ + %graph (graph +.children.n) + == + == + :: + ++ post + |= p=^post + ^- json + %- pairs + :~ [%author (ship author.p)] + [%index (index index.p)] + [%time-sent (time time-sent.p)] + [%contents [%a (turn contents.p content)]] + [%hash ?~(hash.p ~ s+(scot %ux u.hash.p))] + [%signatures (signatures signatures.p)] + == + :: + ++ content + |= c=^content + ^- json + ?- -.c + %text (frond %text s+text.c) + %url (frond %url s+url.c) + %reference (frond %reference (uid uid.c)) + %code + %+ frond %code + %- pairs + :- [%expression s+expression.c] + :_ ~ + :- %output + :: virtualize output rendering, +tank:enjs:format might crash + :: + =/ result=(each (list json) tang) + (mule |.((turn output.c tank))) + ?- -.result + %& a+p.result + %| a+[a+[%s '[[output rendering error]]']~]~ + == + == :: ++ nodes - |= n=(map ^index node) + |= m=(map ^index ^node) ^- json - *json + :- %a + %+ turn ~(tap by m) + |= [n=^index o=^node] + ^- json + %- pairs + :~ [%index (index n)] + [%node (node o)] + == :: ++ indices |= i=(set ^index) ^- json - *json + [%a (turn ~(tap in i) index)] :: ++ uid |= u=^uid ^- json - *json + %- pairs + :~ [%resource (enjs:res resource.u)] + [%index (index index.u)] + == :: ++ signatures |= s=^signatures ^- json - *json + [%a (turn ~(tap in s) signature)] + :: + ++ signature + |= s=^signature + ^- json + %- pairs + :~ [%signature s+(scot %ux p.s)] + [%ship (ship q.s)] + [%life (numb r.s)] + == -- -- :: diff --git a/pkg/arvo/sur/post.hoon b/pkg/arvo/sur/post.hoon index 20b0bd6d67..fc778b00d3 100644 --- a/pkg/arvo/sur/post.hoon +++ b/pkg/arvo/sur/post.hoon @@ -27,8 +27,8 @@ == :: +$ content - $% [%text =cord] - [%url =cord] + $% [%text text=cord] + [%url url=cord] [%code expression=cord output=(list tank)] [%reference =uid] :: [%cage =cage] From 877138a464af10760780546f3cf31ab4482d1a8a Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 11 Jun 2020 14:25:49 -0400 Subject: [PATCH 012/543] graph-store: stubbed out a currently non-compiling json decoding --- pkg/arvo/lib/graph-store.hoon | 121 +++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index fdbe6dcf81..7d058f2d22 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -6,6 +6,11 @@ =, sur =, pos |% +++ nu :: parse number as hex + |= jon/json + ?> ?=({$s *} jon) + (rash p.jon hex) +:: ++ orm ((or-map atom node) lth) ++ orm-log ((or-map time action) lth) :: @@ -198,7 +203,121 @@ ++ action |= =json ^- ^action - !! + :- %0 + ^- action-0 + =< (decode json) + |% + ++ decode + %- of + :~ [%add-graph add-graph] + [%remove-graph remove-graph] + [%add-nodes add-nodes] + [%remove-nodes remove-nodes] + [%add-signatures add-signatures] + [%remove-signatures remove-signatures] + [%add-tags add-tags] + [%remove-tags remove-tags] + == + :: + ++ add-graph + %- ot + :~ [%resource dejs:res] + [%graph !!] + == + :: + :: TODO: convert between normal hoon map and mop + :: + ++ remove-graph + (ot [%resource dejs:res]~) + :: + ++ add-nodes + %- ot + :~ [%resource dejs:res] + [%nodes nodes] + == + :: + ++ nodes (op index node) + :: + ++ node + %- ot + :~ [%post post] + [%children (ot [%empty ul]~)] + == + :: + ++ post + %- ot + :~ [%author (su ;~(pfix sig fed:ag))] + [%index index] + [%time-sent di] + [%contents (ar content)] + [%hash (mu nu)] + [%signatures (as signature)] + == + :: + ++ content + %- of + :~ [%text so] + [%url so] + [%code eval] + == + :: + ++ eval + |= a=^json + ^- [cord (list tank)] + =, ^? dejs-soft:format + =+ exp=((ot expression+so ~) a) + %- need + ?~ exp [~ '' ~] + :+ ~ u.exp + :: NOTE: when sending, if output is an empty list, + :: graph-store will evaluate + (fall ((ot output+(ar dank) ~) a) ~) + :: + ++ remove-nodes + %- ot + :~ [%resource dejs:res] + [%indices (as index)] + == + :: + ++ add-signatures + %- ot + :~ [%uid uid] + [%signatures (as signature)] + == + :: + ++ remove-signatures + %- ot + :~ [%uid uid] + [%signatures (as signature)] + == + :: + ++ signature + %- ot + :~ [%hash nu] + [%ship (su ;~(pfix sig fed:ag))] + [%life ni] + == + :: + ++ uid + %- ot + :~ [%resource dejs:res] + [%index index] + == + :: + ++ index (su ;~(pfix net (more net dem))) + :: + ++ add-tags + %- ot + :~ [%term (se %tas)] + [%resource dejs:res] + == + :: + ++ remove-tags + %- ot + :~ [%term (se %tas)] + [%resource dejs:res] + == + -- -- :: ++ create From b0fa0668b320b293575f4f265e826e73d75d1b09 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 11 Jun 2020 15:30:19 -0400 Subject: [PATCH 013/543] wip: json decoding --- pkg/arvo/app/graph-store.hoon | 140 +++++++++++----------- pkg/arvo/lib/graph-store.hoon | 217 ++++++++++++++++++---------------- pkg/arvo/sur/graph-store.hoon | 6 +- 3 files changed, 190 insertions(+), 173 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index b287f8f5f2..0a4981d91d 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -1,4 +1,4 @@ -/+ store=graph-store, sigs=signatures, *or-map, default-agent, dbug +/+ store=graph-store, sigs=signatures, default-agent, dbug |% +$ card card:agent:gall +$ versioned-state @@ -42,25 +42,25 @@ |^ ?> ?=(%0 -.action) ?- +<.action - %add-graph (add-graph +>.action) + ::%add-graph (add-graph +>.action) %remove-graph (remove-graph +>.action) - %add-nodes (add-nodes +>.action) - %remove-nodes (remove-nodes +>.action) +:: %add-nodes (add-nodes +>.action) +:: %remove-nodes (remove-nodes +>.action) %add-signatures (add-signatures +>.action) %remove-signatures (remove-signatures +>.action) %add-tag (add-tag +>.action) %remove-tag (remove-tag +>.action) == :: - ++ add-graph - |= [=resource:store =graph:store] - ^- (quip card _state) - ?< (~(has by graphs) resource) - :- (give [/updates /keys ~] [%add-graph resource graph]) - %_ state - graphs (~(put by graphs) resource graph) - action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) - == +:: ++ add-graph +:: |= [=resource:store =graph:store] +:: ^- (quip card _state) +:: ?< (~(has by graphs) resource) +:: :- (give [/updates /keys ~] [%add-graph resource graph]) +:: %_ state +:: graphs (~(put by graphs) resource graph) +:: action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) +:: == :: ++ remove-graph |= =resource:store @@ -75,20 +75,20 @@ ++ add-nodes |= [=resource:store nodes=(map index:store node:store)] ^- (quip card _state) - |^ - =/ =graph:store (~(got by graphs) resource) - =/ =action-log:store (~(got by action-logs) resource) - =. action-log - (put:orm-log action-log now.bowl [%0 [%add-nodes resource nodes]]) - :: - :- (give [/updates]~ [%add-nodes resource nodes]) - %_ state - action-logs (~(put by action-logs) resource action-log) - graphs - %+ ~(put by graphs) - resource - (add-node-list resource graph ~(tap by nodes)) - == + |^ [~ state] +:: =/ =graph:store (~(got by graphs) resource) +:: =/ =action-log:store (~(got by action-logs) resource) +:: =. action-log +:: (put:orm-log action-log now.bowl [%0 [%add-nodes resource nodes]]) +:: :: +:: :- (give [/updates]~ [%add-nodes resource nodes]) +:: %_ state +:: action-logs (~(put by action-logs) resource action-log) +:: graphs +:: %+ ~(put by graphs) +:: resource +:: (add-node-list resource graph ~(tap by nodes)) +:: == :: ++ add-node-list |= $: =resource:store @@ -168,20 +168,20 @@ ++ remove-nodes |= [=resource:store indices=(set index:store)] ^- (quip card _state) - |^ - =/ =graph:store (~(got by graphs) resource) - =/ =action-log:store (~(got by action-logs) resource) - =. action-log - (put:orm-log action-log now.bowl [%0 [%remove-nodes resource indices]]) - :: - :- (give [/updates]~ [%remove-nodes resource indices]) - %_ state - action-logs (~(put by action-logs) resource action-log) - graphs - %+ ~(put by graphs) - resource - (remove-indices resource graph ~(tap in indices)) - == + |^ [~ state] +:: =/ =graph:store (~(got by graphs) resource) +:: =/ =action-log:store (~(got by action-logs) resource) +:: =. action-log +:: (put:orm-log action-log now.bowl [%0 [%remove-nodes resource indices]]) +:: :: +:: :- (give [/updates]~ [%remove-nodes resource indices]) +:: %_ state +:: action-logs (~(put by action-logs) resource action-log) +:: graphs +:: %+ ~(put by graphs) +:: resource +:: (remove-indices resource graph ~(tap in indices)) +:: == :: ++ remove-indices |= [=resource:store =graph:store indices=(list index:store)] @@ -218,19 +218,19 @@ ++ add-signatures |= [=uid:store =signatures:store] ^- (quip card _state) - |^ - =* resource resource.uid - =/ =graph:store (~(got by graphs) resource) - =/ =action-log:store (~(got by action-logs) resource) - =. action-log - (put:orm-log action-log now.bowl [%0 [%add-signatures uid signatures]]) - :: - :- (give [/updates]~ [%add-signatures uid signatures]) - %_ state - action-logs (~(put by action-logs) resource action-log) - graphs - (~(put by graphs) resource (add-at-index graph index.uid signatures)) - == + |^ [~ state] +:: =* resource resource.uid +:: =/ =graph:store (~(got by graphs) resource) +:: =/ =action-log:store (~(got by action-logs) resource) +:: =. action-log +:: (put:orm-log action-log now.bowl [%0 [%add-signatures uid signatures]]) +:: :: +:: :- (give [/updates]~ [%add-signatures uid signatures]) +:: %_ state +:: action-logs (~(put by action-logs) resource action-log) +:: graphs +:: (~(put by graphs) resource (add-at-index graph index.uid signatures)) +:: == :: ++ add-at-index |= [=graph:store =index:store =signatures:store] @@ -262,22 +262,22 @@ ++ remove-signatures |= [=uid:store =signatures:store] ^- (quip card _state) - |^ - =* resource resource.uid - =/ =graph:store (~(got by graphs) resource) - =/ =action-log:store (~(got by action-logs) resource) - =. action-log - %^ put:orm-log action-log - now.bowl - [%0 [%remove-signatures uid signatures]] - :: - :- (give [/updates]~ [%remove-signatures uid signatures]) - %_ state - action-logs (~(put by action-logs) resource action-log) - graphs - %+ ~(put by graphs) resource - (remove-at-index graph index.uid signatures) - == + |^ [~ state] +:: =* resource resource.uid +:: =/ =graph:store (~(got by graphs) resource) +:: =/ =action-log:store (~(got by action-logs) resource) +:: =. action-log +:: %^ put:orm-log action-log +:: now.bowl +:: [%0 [%remove-signatures uid signatures]] +:: :: +:: :- (give [/updates]~ [%remove-signatures uid signatures]) +:: %_ state +:: action-logs (~(put by action-logs) resource action-log) +:: graphs +:: %+ ~(put by graphs) resource +:: (remove-at-index graph index.uid signatures) +:: == :: ++ remove-at-index |= [=graph:store =index:store =signatures:store] diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 7d058f2d22..182a9cb665 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -2,15 +2,32 @@ /+ res=resource, *or-map =< [sur .] =< [pos .] -=< [res .] =, sur =, pos |% +:: NOTE: move these functions to zuse ++ nu :: parse number as hex |= jon/json ?> ?=({$s *} jon) (rash p.jon hex) :: +++ re :: recursive reparsers + |* {gar/* sef/_|.(fist:dejs-soft:format)} + |= jon/json + ^- (unit _gar) + =- ~! gar ~! (need -) - + ((sef) jon) +:: +++ dank :: tank + ^- $-(json (unit tank)) + =, ^? dejs-soft:format + %+ re *tank |. ~+ + %- of :~ + leaf+sa + palm+(ot style+(ot mid+sa cap+sa open+sa close+sa ~) lines+(ar dank) ~) + rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~) + == +:: ++ orm ((or-map atom node) lth) ++ orm-log ((or-map time action) lth) :: @@ -30,30 +47,30 @@ %keys [%keys [%a (turn ~(tap in resources.upd) enjs:res)]] :: - %add-graph - :- %add-graph - %- pairs - :~ [%resource (enjs:res resource.upd)] - [%graph (graph graph.upd)] - == +:: %add-graph +:: :- %add-graph +:: %- pairs +:: :~ [%resource (enjs:res resource.upd)] +:: [%graph (graph graph.upd)] +:: == :: %remove-graph [%remove-graph (enjs:res resource.upd)] :: - %add-nodes - :- %add-nodes - %- pairs - :~ [%resource (enjs:res resource.upd)] - [%nodes (nodes nodes.upd)] - == - :: - %remove-nodes - :- %remove-nodes - %- pairs - :~ [%resource (enjs:res resource.upd)] - [%indices (indices indices.upd)] - == +:: %add-nodes +:: :- %add-nodes +:: %- pairs +:: :~ [%resource (enjs:res resource.upd)] +:: [%nodes (nodes nodes.upd)] +:: == :: +:: %remove-nodes +:: :- %remove-nodes +:: %- pairs +:: :~ [%resource (enjs:res resource.upd)] +:: [%indices (indices indices.upd)] +:: == +:: :: %add-signatures :- %add-signatures %- pairs @@ -201,84 +218,83 @@ =, dejs:format |% ++ action - |= =json + |= jon=json ^- ^action :- %0 ^- action-0 - =< (decode json) + =< (decode jon) |% ++ decode %- of - :~ [%add-graph add-graph] + :~ +:: [%add-graph add-graph] [%remove-graph remove-graph] - [%add-nodes add-nodes] - [%remove-nodes remove-nodes] - [%add-signatures add-signatures] +:: [%add-nodes add-nodes] +:: [%remove-nodes remove-nodes] +:: [%add-signatures add-signatures] [%remove-signatures remove-signatures] - [%add-tags add-tags] - [%remove-tags remove-tags] + [%add-tag add-tag] + [%remove-tag remove-tag] == :: - ++ add-graph - %- ot - :~ [%resource dejs:res] - [%graph !!] - == +:: ++ add-graph +:: %- ot +:: :~ [%resource dejs:res] +:: [%graph !!] +:: == :: - :: TODO: convert between normal hoon map and mop + ++ remove-graph (ot [%resource dejs:res]~) :: - ++ remove-graph - (ot [%resource dejs:res]~) +:: ++ add-nodes +:: %- ot +:: :~ [%resource dejs:res] +:: [%nodes nodes] +:: == :: - ++ add-nodes - %- ot - :~ [%resource dejs:res] - [%nodes nodes] - == +:: ++ nodes (op index node) :: - ++ nodes (op index node) - :: - ++ node - %- ot - :~ [%post post] - [%children (ot [%empty ul]~)] - == - :: - ++ post - %- ot - :~ [%author (su ;~(pfix sig fed:ag))] - [%index index] - [%time-sent di] - [%contents (ar content)] - [%hash (mu nu)] - [%signatures (as signature)] - == - :: - ++ content - %- of - :~ [%text so] - [%url so] - [%code eval] - == - :: - ++ eval - |= a=^json - ^- [cord (list tank)] - =, ^? dejs-soft:format - =+ exp=((ot expression+so ~) a) - %- need - ?~ exp [~ '' ~] - :+ ~ u.exp - :: NOTE: when sending, if output is an empty list, - :: graph-store will evaluate - (fall ((ot output+(ar dank) ~) a) ~) - :: - ++ remove-nodes - %- ot - :~ [%resource dejs:res] - [%indices (as index)] - == +:: ++ node +:: %- ot +:: :~ [%post post] +:: [%children (ot [%empty ul]~)] +:: == +:: :: +:: ++ post +:: %- ot +:: :~ [%author (su ;~(pfix sig fed:ag))] +:: [%index index] +:: [%time-sent di] +:: [%contents (ar content)] +:: [%hash (mu nu)] +:: [%signatures (as signature)] +:: == +:: :: +:: ++ content +:: %- of +:: :~ [%text so] +:: [%url so] +:: [%reference uid] +:: [%code eval] +:: == +:: :: +:: ++ eval +:: |= a=^json +:: ^- [cord (list tank)] +:: =, ^? dejs-soft:format +:: =+ exp=((ot expression+so ~) a) +:: %- need +:: ?~ exp [~ '' ~] +:: :+ ~ u.exp +:: :: NOTE: when sending, if output is an empty list, +:: :: graph-store will evaluate +:: (fall ((ot output+(ar dank) ~) a) ~) :: +:: ++ remove-nodes +:: %- ot +:: :~ [%resource dejs:res] +:: [%indices (as index)] +:: == +:: :: ++ add-signatures %- ot :~ [%uid uid] @@ -306,31 +322,32 @@ :: ++ index (su ;~(pfix net (more net dem))) :: - ++ add-tags + ++ add-tag %- ot - :~ [%term (se %tas)] + :~ [%term so] [%resource dejs:res] == :: - ++ remove-tags + ++ remove-tag %- ot - :~ [%term (se %tas)] + :~ [%term so] [%resource dejs:res] == -- -- :: -++ create - |_ [our=ship now=time] - ++ post - |= [=index contents=(list content)] - ^- ^post - :* our - index - now - contents - ~ - *signatures - == - -- +::++ create +:: |_ [our=ship now=time] +:: ++ post +:: |= [=index contents=(list content)] +:: ^- ^post +:: :* our +:: index +:: now +:: contents +:: ~ +:: *signatures +:: == +:: -- +:: -- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index 5170d8e481..cdf4ab5d90 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -33,11 +33,11 @@ == :: +$ action-0 - $% [%add-graph =resource =graph] + $% :: [%add-graph =resource =graph] [%remove-graph =resource] :: - [%add-nodes =resource nodes=(map index node)] - [%remove-nodes =resource indices=(set index)] +:: [%add-nodes =resource nodes=(map index node)] +:: [%remove-nodes =resource indices=(set index)] :: [%add-signatures =uid =signatures] [%remove-signatures =uid =signatures] From 2e5bbd74236c52e1a907b27d9de3102eadc26b25 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 11 Jun 2020 15:30:35 -0400 Subject: [PATCH 014/543] wip: graph-store JS api --- pkg/interface/src/api/graph.js | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 pkg/interface/src/api/graph.js diff --git a/pkg/interface/src/api/graph.js b/pkg/interface/src/api/graph.js new file mode 100644 index 0000000000..86e28af8c2 --- /dev/null +++ b/pkg/interface/src/api/graph.js @@ -0,0 +1,80 @@ +import BaseApi from './base'; + +class PrivateHelper extends BaseApi { + graphAction(data) { + this.action('graph-store', 'graph-action', data); + } + + addGraph(resource, graph) { + this.graphAction({ + 'add-graph': { + resource, + graph + } + }); + } + + removeGraph(resource) { + this.graphAction({ + 'remove-graph': { + resource + } + }); + } + + addNodes(resource, nodes) { + this.graphAction({ + 'add-nodes': { + resource, + nodes + } + }); + } + + removeNodes(resource, indices) { + this.graphAction({ + 'remove-nodes': { + resource, + indices + } + }); + } + + addSignatures() { + this.graphAction(); + } + + removeSignatures() { + this.graphAction(); + } + + addTag() { + this.graphAction(); + } + + removeTag() { + this.graphAction(); + } +} + +export default class GraphApi { + constructor(ship, channel, store) { + const helper = new PrivateHelper(ship, channel, store); + + this.ship = ship; + this.subscribe = helper.subscribe.bind(helper); + + this.addGraph = helper.addGraph.bind(helper); + this.removeGraph = helper.removeGraph.bind(helper); + + this.addNodes = helper.addNodes.bind(helper); + this.removeNodes = helper.removeNodes.bind(helper); + + this.addSignatures = helper.addSignatures.bind(helper); + this.removeSignatures = helper.removeSignatures.bind(helper); + + this.addTag = helper.addTag.bind(helper); + this.removeTag = helper.removeTag.bind(helper); + } +} + From 37f332dcb6c3e7a779e88e3127df1fa8aeec79ca Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 13:26:45 -0400 Subject: [PATCH 015/543] or-map: fix specific assertion that should have been general --- pkg/arvo/lib/or-map.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/lib/or-map.hoon b/pkg/arvo/lib/or-map.hoon index 060b0f631f..a582fe9afe 100644 --- a/pkg/arvo/lib/or-map.hoon +++ b/pkg/arvo/lib/or-map.hoon @@ -276,7 +276,7 @@ (del-span tre %end end) ?~ end (del-span tre %start start) - ?> (lth u.start u.end) + ?> (compare u.start u.end) =. tre (del-span tre %start start) (del-span tre %end end) :: From 6493c75463e4878ece625b97734c8f00a802615c Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 13:27:43 -0400 Subject: [PATCH 016/543] wip: all JSON decoders but %add-graph work --- pkg/arvo/app/graph-store.hoon | 138 ++++++++++------------- pkg/arvo/lib/graph-store.hoon | 205 +++++++++++++++++++++++----------- pkg/arvo/sur/graph-store.hoon | 6 +- 3 files changed, 200 insertions(+), 149 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 0a4981d91d..c2101c8e5e 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -42,10 +42,10 @@ |^ ?> ?=(%0 -.action) ?- +<.action - ::%add-graph (add-graph +>.action) +:: %add-graph (add-graph +>.action) %remove-graph (remove-graph +>.action) -:: %add-nodes (add-nodes +>.action) -:: %remove-nodes (remove-nodes +>.action) + %add-nodes (add-nodes +>.action) + %remove-nodes (remove-nodes +>.action) %add-signatures (add-signatures +>.action) %remove-signatures (remove-signatures +>.action) %add-tag (add-tag +>.action) @@ -75,20 +75,20 @@ ++ add-nodes |= [=resource:store nodes=(map index:store node:store)] ^- (quip card _state) - |^ [~ state] -:: =/ =graph:store (~(got by graphs) resource) -:: =/ =action-log:store (~(got by action-logs) resource) -:: =. action-log -:: (put:orm-log action-log now.bowl [%0 [%add-nodes resource nodes]]) -:: :: -:: :- (give [/updates]~ [%add-nodes resource nodes]) -:: %_ state -:: action-logs (~(put by action-logs) resource action-log) -:: graphs -:: %+ ~(put by graphs) -:: resource -:: (add-node-list resource graph ~(tap by nodes)) -:: == + |^ + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + (put:orm-log action-log now.bowl [%0 [%add-nodes resource nodes]]) + :: + :- (give [/updates]~ [%add-nodes resource nodes]) + %_ state + action-logs (~(put by action-logs) resource action-log) + graphs + %+ ~(put by graphs) + resource + (add-node-list resource graph ~(tap by nodes)) + == :: ++ add-node-list |= $: =resource:store @@ -142,8 +142,6 @@ our.bowl .^(=life %j /=life/(scot %p our.bowl)) == - :: multiple indices left in list - :: ~| "index does not exist to add a node to!" =/ parent=node:store (need (get:orm graph atom)) %_ parent @@ -155,11 +153,7 @@ parent-hash hash.post.parent graph ?: ?=(%graph -.children.parent) - :: recurse into children - :: p.children.parent - :: replace empty graph with graph containing one child - :: (gas:orm ~ ~) == == @@ -168,20 +162,20 @@ ++ remove-nodes |= [=resource:store indices=(set index:store)] ^- (quip card _state) - |^ [~ state] -:: =/ =graph:store (~(got by graphs) resource) -:: =/ =action-log:store (~(got by action-logs) resource) -:: =. action-log -:: (put:orm-log action-log now.bowl [%0 [%remove-nodes resource indices]]) -:: :: -:: :- (give [/updates]~ [%remove-nodes resource indices]) -:: %_ state -:: action-logs (~(put by action-logs) resource action-log) -:: graphs -:: %+ ~(put by graphs) -:: resource -:: (remove-indices resource graph ~(tap in indices)) -:: == + |^ + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + (put:orm-log action-log now.bowl [%0 [%remove-nodes resource indices]]) + :: + :- (give [/updates]~ [%remove-nodes resource indices]) + %_ state + action-logs (~(put by action-logs) resource action-log) + graphs + %+ ~(put by graphs) + resource + (remove-indices resource graph ~(tap in indices)) + == :: ++ remove-indices |= [=resource:store =graph:store indices=(list index:store)] @@ -201,14 +195,10 @@ :: ?~ t.index +:`[* graph:store]`(del:orm graph atom) - :: multiple indices left in list - :: ~| "parent index does not exist to remove a node from!" =/ =node:store (need (get:orm graph atom)) ~| "child index does not exist to remove a node from!" ?> ?=(%graph -.children.node) - :: recurse into children - :: %^ put:orm graph atom @@ -218,19 +208,19 @@ ++ add-signatures |= [=uid:store =signatures:store] ^- (quip card _state) - |^ [~ state] -:: =* resource resource.uid -:: =/ =graph:store (~(got by graphs) resource) -:: =/ =action-log:store (~(got by action-logs) resource) -:: =. action-log -:: (put:orm-log action-log now.bowl [%0 [%add-signatures uid signatures]]) -:: :: -:: :- (give [/updates]~ [%add-signatures uid signatures]) -:: %_ state -:: action-logs (~(put by action-logs) resource action-log) -:: graphs -:: (~(put by graphs) resource (add-at-index graph index.uid signatures)) -:: == + |^ + =* resource resource.uid + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + (put:orm-log action-log now.bowl [%0 [%add-signatures uid signatures]]) + :: + :- (give [/updates]~ [%add-signatures uid signatures]) + %_ state + action-logs (~(put by action-logs) resource action-log) + graphs + (~(put by graphs) resource (add-at-index graph index.uid signatures)) + == :: ++ add-at-index |= [=graph:store =index:store =signatures:store] @@ -250,34 +240,30 @@ ~| "signatures did not match public keys!" ?> (are-signatures-valid:sigs signatures u.hash.post.node now.bowl) node(signatures.post (~(uni in signatures) signatures.post.node)) - :: multiple indices left in list - :: ~| "child graph does not exist to add signatures to!" ?> ?=(%graph -.children.node) - :: recurse into children - :: node(p.children $(graph p.children.node, index t.index)) -- :: ++ remove-signatures |= [=uid:store =signatures:store] ^- (quip card _state) - |^ [~ state] -:: =* resource resource.uid -:: =/ =graph:store (~(got by graphs) resource) -:: =/ =action-log:store (~(got by action-logs) resource) -:: =. action-log -:: %^ put:orm-log action-log -:: now.bowl -:: [%0 [%remove-signatures uid signatures]] -:: :: -:: :- (give [/updates]~ [%remove-signatures uid signatures]) -:: %_ state -:: action-logs (~(put by action-logs) resource action-log) -:: graphs -:: %+ ~(put by graphs) resource -:: (remove-at-index graph index.uid signatures) -:: == + |^ + =* resource resource.uid + =/ =graph:store (~(got by graphs) resource) + =/ =action-log:store (~(got by action-logs) resource) + =. action-log + %^ put:orm-log action-log + now.bowl + [%0 [%remove-signatures uid signatures]] + :: + :- (give [/updates]~ [%remove-signatures uid signatures]) + %_ state + action-logs (~(put by action-logs) resource action-log) + graphs + %+ ~(put by graphs) resource + (remove-at-index graph index.uid signatures) + == :: ++ remove-at-index |= [=graph:store =index:store =signatures:store] @@ -293,12 +279,8 @@ atom ?~ t.index node(signatures.post (~(dif in signatures) signatures.post.node)) - :: multiple indices left in list - :: ~| "child graph does not exist to add signatures to!" ?> ?=(%graph -.children.node) - :: recurse into children - :: node(p.children $(graph p.children.node, index t.index)) -- :: diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 182a9cb665..211ee4b804 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -57,20 +57,20 @@ %remove-graph [%remove-graph (enjs:res resource.upd)] :: -:: %add-nodes -:: :- %add-nodes -:: %- pairs -:: :~ [%resource (enjs:res resource.upd)] -:: [%nodes (nodes nodes.upd)] -:: == + %add-nodes + :- %add-nodes + %- pairs + :~ [%resource (enjs:res resource.upd)] + [%nodes (nodes nodes.upd)] + == + :: + %remove-nodes + :- %remove-nodes + %- pairs + :~ [%resource (enjs:res resource.upd)] + [%indices (indices indices.upd)] + == :: -:: %remove-nodes -:: :- %remove-nodes -:: %- pairs -:: :~ [%resource (enjs:res resource.upd)] -:: [%indices (indices indices.upd)] -:: == -:: :: %add-signatures :- %add-signatures %- pairs @@ -117,8 +117,7 @@ ^- json =/ j=^tape "" |- - ?~ i - [%s (crip j)] + ?~ i [%s (crip j)] =/ k=json (numb i.i) ?> ?=(%n -.k) %_ $ @@ -217,6 +216,71 @@ ++ dejs =, dejs:format |% + ++ or :: parse keys of ordered map + |* [fel=rule wit=fist] + =/ key=mold _(wonk *fel) + =/ val=mold _*wit + |= ord=$-([key key] ?) + ^- fist + =/ or-mp ((or-map key val) ord) + |= jan=json + =/ jom ((om wit) jan) + %+ gas:or-mp ~ + %+ turn ~(tap by jom) + |* [a=cord b=*] + ^- [key val] + => .(+< [a b]=+<) + [(rash a fel) b] + :: + ++ graph (or dem node) + :: + ++ node + %- ot + :~ [%post post] + :: TODO: support adding nodes with children by supporting the + :: graph key + [%children (of [%empty ul]~)] + == + :: + ++ post + %- ot + :~ [%author (su ;~(pfix sig fed:ag))] + [%index index] + [%time-sent di] + [%contents (ar content)] + [%hash (mu nu)] + [%signatures (as signature)] + == + :: + ++ content + %- of + :~ [%text so] + [%url so] + [%reference uid] + [%code eval] + == + :: + ++ eval + |= a=^json + ^- [cord (list tank)] + =, ^? dejs-soft:format + =+ exp=((ot expression+so ~) a) + %- need + ?~ exp [~ '' ~] + :+ ~ u.exp + :: NOTE: when sending, if output is an empty list, + :: graph-store will evaluate + (fall ((ot output+(ar dank) ~) a) ~) + :: + ++ signature + %- ot + :~ [%hash nu] + [%ship (su ;~(pfix sig fed:ag))] + [%life ni] + == + :: + ++ index (su ;~(pfix net (more net dem))) + :: ++ action |= jon=json ^- ^action @@ -226,12 +290,11 @@ |% ++ decode %- of - :~ -:: [%add-graph add-graph] + :~ ::[%add-graph add-graph] [%remove-graph remove-graph] -:: [%add-nodes add-nodes] -:: [%remove-nodes remove-nodes] -:: [%add-signatures add-signatures] + [%add-nodes add-nodes] + [%remove-nodes remove-nodes] + [%add-signatures add-signatures] [%remove-signatures remove-signatures] [%add-tag add-tag] [%remove-tag remove-tag] @@ -240,61 +303,67 @@ :: ++ add-graph :: %- ot :: :~ [%resource dejs:res] -:: [%graph !!] +:: [%graph graph] :: == + :: + :: + ++ graph (or dem node) + :: :: ++ remove-graph (ot [%resource dejs:res]~) :: -:: ++ add-nodes -:: %- ot -:: :~ [%resource dejs:res] -:: [%nodes nodes] -:: == + ++ add-nodes + %- ot + :~ [%resource dejs:res] + [%nodes nodes] + == :: -:: ++ nodes (op index node) + ++ nodes (op ;~(pfix net (more net dem)) node) :: -:: ++ node -:: %- ot -:: :~ [%post post] -:: [%children (ot [%empty ul]~)] -:: == -:: :: -:: ++ post -:: %- ot -:: :~ [%author (su ;~(pfix sig fed:ag))] -:: [%index index] -:: [%time-sent di] -:: [%contents (ar content)] -:: [%hash (mu nu)] -:: [%signatures (as signature)] -:: == -:: :: -:: ++ content -:: %- of -:: :~ [%text so] -:: [%url so] -:: [%reference uid] -:: [%code eval] -:: == -:: :: -:: ++ eval -:: |= a=^json -:: ^- [cord (list tank)] -:: =, ^? dejs-soft:format -:: =+ exp=((ot expression+so ~) a) -:: %- need -:: ?~ exp [~ '' ~] -:: :+ ~ u.exp -:: :: NOTE: when sending, if output is an empty list, -:: :: graph-store will evaluate -:: (fall ((ot output+(ar dank) ~) a) ~) + ++ node + %- ot + :~ [%post post] + :: TODO: support adding nodes with children by supporting the + :: graph key + [%children (of [%empty ul]~)] + == + :: + ++ post + %- ot + :~ [%author (su ;~(pfix sig fed:ag))] + [%index index] + [%time-sent di] + [%contents (ar content)] + [%hash (mu nu)] + [%signatures (as signature)] + == + :: + ++ content + %- of + :~ [%text so] + [%url so] + [%reference uid] + [%code eval] + == + :: + ++ eval + |= a=^json + ^- [cord (list tank)] + =, ^? dejs-soft:format + =+ exp=((ot expression+so ~) a) + %- need + ?~ exp [~ '' ~] + :+ ~ u.exp + :: NOTE: when sending, if output is an empty list, + :: graph-store will evaluate + (fall ((ot output+(ar dank) ~) a) ~) + :: + ++ remove-nodes + %- ot + :~ [%resource dejs:res] + [%indices (as index)] + == :: -:: ++ remove-nodes -:: %- ot -:: :~ [%resource dejs:res] -:: [%indices (as index)] -:: == -:: :: ++ add-signatures %- ot :~ [%uid uid] diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index cdf4ab5d90..8b98046e62 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -33,11 +33,11 @@ == :: +$ action-0 - $% :: [%add-graph =resource =graph] + $% ::[%add-graph =resource =graph] [%remove-graph =resource] :: -:: [%add-nodes =resource nodes=(map index node)] -:: [%remove-nodes =resource indices=(set index)] + [%add-nodes =resource nodes=(map index node)] + [%remove-nodes =resource indices=(set index)] :: [%add-signatures =uid =signatures] [%remove-signatures =uid =signatures] From 07cf3744626fee8506f7a526d08ef3b06bc4e4a8 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 13:50:22 -0400 Subject: [PATCH 017/543] graph-store: all json encoders/decoders work --- pkg/arvo/app/graph-store.hoon | 20 +++--- pkg/arvo/lib/graph-store.hoon | 128 ++++++++++------------------------ pkg/arvo/sur/graph-store.hoon | 2 +- 3 files changed, 46 insertions(+), 104 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index c2101c8e5e..561cf04b3c 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -42,7 +42,7 @@ |^ ?> ?=(%0 -.action) ?- +<.action -:: %add-graph (add-graph +>.action) + %add-graph (add-graph +>.action) %remove-graph (remove-graph +>.action) %add-nodes (add-nodes +>.action) %remove-nodes (remove-nodes +>.action) @@ -52,15 +52,15 @@ %remove-tag (remove-tag +>.action) == :: -:: ++ add-graph -:: |= [=resource:store =graph:store] -:: ^- (quip card _state) -:: ?< (~(has by graphs) resource) -:: :- (give [/updates /keys ~] [%add-graph resource graph]) -:: %_ state -:: graphs (~(put by graphs) resource graph) -:: action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) -:: == + ++ add-graph + |= [=resource:store =graph:store] + ^- (quip card _state) + ?< (~(has by graphs) resource) + :- (give [/updates /keys ~] [%add-graph resource graph]) + %_ state + graphs (~(put by graphs) resource graph) + action-logs (~(put by action-logs) resource (gas:orm-log ~ ~)) + == :: ++ remove-graph |= =resource:store diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 211ee4b804..449134e9a2 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -47,12 +47,12 @@ %keys [%keys [%a (turn ~(tap in resources.upd) enjs:res)]] :: -:: %add-graph -:: :- %add-graph -:: %- pairs -:: :~ [%resource (enjs:res resource.upd)] -:: [%graph (graph graph.upd)] -:: == + %add-graph + :- %add-graph + %- pairs + :~ [%resource (enjs:res resource.upd)] + [%graph (graph graph.upd)] + == :: %remove-graph [%remove-graph (enjs:res resource.upd)] @@ -216,71 +216,6 @@ ++ dejs =, dejs:format |% - ++ or :: parse keys of ordered map - |* [fel=rule wit=fist] - =/ key=mold _(wonk *fel) - =/ val=mold _*wit - |= ord=$-([key key] ?) - ^- fist - =/ or-mp ((or-map key val) ord) - |= jan=json - =/ jom ((om wit) jan) - %+ gas:or-mp ~ - %+ turn ~(tap by jom) - |* [a=cord b=*] - ^- [key val] - => .(+< [a b]=+<) - [(rash a fel) b] - :: - ++ graph (or dem node) - :: - ++ node - %- ot - :~ [%post post] - :: TODO: support adding nodes with children by supporting the - :: graph key - [%children (of [%empty ul]~)] - == - :: - ++ post - %- ot - :~ [%author (su ;~(pfix sig fed:ag))] - [%index index] - [%time-sent di] - [%contents (ar content)] - [%hash (mu nu)] - [%signatures (as signature)] - == - :: - ++ content - %- of - :~ [%text so] - [%url so] - [%reference uid] - [%code eval] - == - :: - ++ eval - |= a=^json - ^- [cord (list tank)] - =, ^? dejs-soft:format - =+ exp=((ot expression+so ~) a) - %- need - ?~ exp [~ '' ~] - :+ ~ u.exp - :: NOTE: when sending, if output is an empty list, - :: graph-store will evaluate - (fall ((ot output+(ar dank) ~) a) ~) - :: - ++ signature - %- ot - :~ [%hash nu] - [%ship (su ;~(pfix sig fed:ag))] - [%life ni] - == - :: - ++ index (su ;~(pfix net (more net dem))) - :: ++ action |= jon=json ^- ^action @@ -290,7 +225,7 @@ |% ++ decode %- of - :~ ::[%add-graph add-graph] + :~ [%add-graph add-graph] [%remove-graph remove-graph] [%add-nodes add-nodes] [%remove-nodes remove-nodes] @@ -300,15 +235,22 @@ [%remove-tag remove-tag] == :: -:: ++ add-graph -:: %- ot -:: :~ [%resource dejs:res] -:: [%graph graph] -:: == - :: - :: - ++ graph (or dem node) + ++ add-graph + %- ot + :~ [%resource dejs:res] + [%graph graph] + == :: + ++ graph + |= a=json + ^- ^graph + =/ or-mp ((or-map atom ^node) lth) + %+ gas:or-mp ~ + %+ turn ~(tap by ((om node) a)) + |* [b=cord c=*] + ^- [atom ^node] + => .(+< [b c]=+<) + [(rash b dem) c] :: ++ remove-graph (ot [%resource dejs:res]~) :: @@ -405,18 +347,18 @@ -- -- :: -::++ create -:: |_ [our=ship now=time] -:: ++ post -:: |= [=index contents=(list content)] -:: ^- ^post -:: :* our -:: index -:: now -:: contents -:: ~ -:: *signatures -:: == -:: -- +++ create + |_ [our=ship now=time] + ++ post + |= [=index contents=(list content)] + ^- ^post + :* our + index + now + contents + ~ + *signatures + == + -- :: -- diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index 8b98046e62..5170d8e481 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -33,7 +33,7 @@ == :: +$ action-0 - $% ::[%add-graph =resource =graph] + $% [%add-graph =resource =graph] [%remove-graph =resource] :: [%add-nodes =resource nodes=(map index node)] From 90a8df104b3151a769da5da5be1a74272cffed56 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 14:02:52 -0400 Subject: [PATCH 018/543] graph-store: wrote basic queries --- pkg/arvo/app/graph-store.hoon | 10 +++++++++- pkg/arvo/sur/graph-store.hoon | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 561cf04b3c..0e4ba59d28 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -331,7 +331,15 @@ |= =path ^- (unit (unit cage)) ?+ path (on-peek:def path) - [%x %keys ~] ``noun+!>(~(key by graphs)) + [%x %keys ~] ``noun+!>(~(key by graphs)) + [%x %tags ~] ``noun+!>(~(key by tag-queries)) + [%x %graph @ @ ~] + =/ =ship (slav %p i.t.t.path) + =/ =term i.t.t.path + =/ graph=(unit graph:store) (~(get by graphs) [ship term]) + ?~ graph + ~ + ``noun+!>(u.graph) == :: ++ on-arvo on-arvo:def diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index 5170d8e481..688845bfb2 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -20,6 +20,7 @@ +$ action-log ((mop time action) lth) :: +$ graph ((mop atom node) lth) +:: +$ internal-graph $~ [%empty ~] $% [%graph p=graph] From 59a4c522323fbd4ad13dea3a89bbfc201499d826 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 14:55:30 -0400 Subject: [PATCH 019/543] graph-view: first sketch --- pkg/arvo/app/graph-view.hoon | 127 +++++++++++++++++++++++++++++++++++ pkg/arvo/lib/graph-view.hoon | 6 ++ pkg/arvo/lib/hood/drum.hoon | 6 +- pkg/arvo/sur/graph-view.hoon | 9 +++ 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 pkg/arvo/app/graph-view.hoon create mode 100644 pkg/arvo/lib/graph-view.hoon create mode 100644 pkg/arvo/sur/graph-view.hoon diff --git a/pkg/arvo/app/graph-view.hoon b/pkg/arvo/app/graph-view.hoon new file mode 100644 index 0000000000..98340eed6b --- /dev/null +++ b/pkg/arvo/app/graph-view.hoon @@ -0,0 +1,127 @@ +/+ view=graph-view, store=graph-store, default-agent, verb, dbug +:: +|% ++$ versioned-state + $% state-0 + == +:: ++$ state-0 + $: %0 + connections=(map atom:store time) + == +:: ++$ card card:agent:gall +-- +:: +=| state-0 +=* state - +:: +%+ verb | +%- agent:dbug +^- agent:gall +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init + ^- (quip card _this) + :_ this + [%pass /updates %agent [our.bowl %graph-store] %watch /updates]~ +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %graph-view-action (view-action !<(action:view vase)) + == + [cards this] + :: + ++ view-action + |= =action:view + ^- (quip card _state) + ?- -.action + %fetch (fetch +.action) + == + :: + ++ scry-for + |* [=mold =path] + .^ mold + %gx + (scot %p our.bowl) + %graph-store + (scot %da now.bowl) + (snoc `^path`path %noun) + == + :: + ++ fetch + |= [conn=atom:store type=fetch-type:view] + ^- (quip card _state) + =/ keys (scry-for resources:store /keys) + :_ state + :- (give conn [%graph-update !>([%0 [%keys keys]])]) + %+ turn ~(tap in keys) + |= [=ship =term] + (give conn [%graph-update !>((add-graph ship term))]) + :: + ++ add-graph + |= [=ship =term] + ^- update:store + :- %0 + :+ %add-graph + [ship term] + (scry-for graph:store /graph/(scot %p ship)/[term]) + :: + ++ give + |= [conn=atom:store =cage] + ^- card + [%give %fact [/updates/(scot %ud conn)]~ cage] + -- +:: +++ on-watch + |= =path + ^- (quip card _this) + ?> (team:title our.bowl src.bowl) + ?+ path (on-watch:def path) + [%updates @ ~] + :- ~ + this(connections (~(put by connections) i.t.path now.bowl)) + == +:: +++ on-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + |^ + ?+ -.sign (on-agent:def wire sign) + %kick + :_ this + [%pass /updates %agent [our.bowl %graph-store] %watch /updates]~ + :: + %fact + ?+ p.cage.sign (on-agent:def wire sign) + %graph-update + :_ this + %+ give + %+ turn ~(tap by connections) + |= [=atom:store *] + ^- path + /updates/(scot %ud atom) + cage.sign + == + == + :: + ++ give + |= [paths=(list path) =cage] + ^- (list card) + [%give %fact paths cage]~ + -- +:: +++ on-save !>(state) +++ on-load on-load:def +++ on-arvo on-arvo:def +++ on-leave on-leave:def +++ on-peek on-peek:def +++ on-fail on-fail:def +-- diff --git a/pkg/arvo/lib/graph-view.hoon b/pkg/arvo/lib/graph-view.hoon new file mode 100644 index 0000000000..f0fa0da122 --- /dev/null +++ b/pkg/arvo/lib/graph-view.hoon @@ -0,0 +1,6 @@ +/- sur=graph-view +^? +=< [sur .] +=, sur +|% +-- diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 71cc5f26df..c51525af62 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -119,6 +119,8 @@ %metadata-hook %s3-store %file-server + %graph-store + %graph-view == :: ++ deft-fish :: default connects @@ -242,7 +244,9 @@ =< (se-born %home %link-listen-hook) =< (se-born %home %link-view) =< (se-born %home %s3-store) - (se-born %home %file-server) + =< (se-born %home %file-server) + =< (se-born %home %graph-store) + (se-born %home %graph-view) . ?> ?=(%5 ver) => (se-born %home %file-server) diff --git a/pkg/arvo/sur/graph-view.hoon b/pkg/arvo/sur/graph-view.hoon new file mode 100644 index 0000000000..0530ffbf84 --- /dev/null +++ b/pkg/arvo/sur/graph-view.hoon @@ -0,0 +1,9 @@ +|% ++$ fetch-type + $% [%all ~] + == +:: ++$ action + $% [%fetch connection=@ type=fetch-type] + == +-- From 8d5fb1668535a50243e3b5e69c9a6d2fd782b396 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 15:07:10 -0400 Subject: [PATCH 020/543] graph-view: working json parsing for fetches --- pkg/arvo/app/graph-view.hoon | 2 +- pkg/arvo/lib/graph-view.hoon | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/app/graph-view.hoon b/pkg/arvo/app/graph-view.hoon index 98340eed6b..c50cb7cf42 100644 --- a/pkg/arvo/app/graph-view.hoon +++ b/pkg/arvo/app/graph-view.hoon @@ -86,7 +86,7 @@ ?> (team:title our.bowl src.bowl) ?+ path (on-watch:def path) [%updates @ ~] - :- ~ + :- [%give %fact ~ %json !>([(frond:enjs:format %graph-view s+'bound')])]~ this(connections (~(put by connections) i.t.path now.bowl)) == :: diff --git a/pkg/arvo/lib/graph-view.hoon b/pkg/arvo/lib/graph-view.hoon index f0fa0da122..1e2adc94e0 100644 --- a/pkg/arvo/lib/graph-view.hoon +++ b/pkg/arvo/lib/graph-view.hoon @@ -3,4 +3,30 @@ =< [sur .] =, sur |% +++ dejs + =, dejs:format + |% + ++ action + |= jon=json + ^- ^action + =< (parse-json jon) + |% + ++ parse-json + %- of + :~ [%fetch fetch] + == + :: + ++ fetch + %- ot + :~ [%connection ni] + [%type fetch-type] + == + :: + ++ fetch-type + %- of + :~ [%all ul] + == + -- + -- + -- From 7d74d1870fd9436812f632acf770e8ed92cf635a Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 15:07:47 -0400 Subject: [PATCH 021/543] graph-js: added demo fetch api / subscription objs --- pkg/interface/src/api/graph.js | 21 ++++++++++++++++---- pkg/interface/src/subscription/graph.js | 26 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 pkg/interface/src/subscription/graph.js diff --git a/pkg/interface/src/api/graph.js b/pkg/interface/src/api/graph.js index 86e28af8c2..04eb5c05a5 100644 --- a/pkg/interface/src/api/graph.js +++ b/pkg/interface/src/api/graph.js @@ -5,7 +5,7 @@ class PrivateHelper extends BaseApi { this.action('graph-store', 'graph-action', data); } - addGraph(resource, graph) { + addGraph(resource = { ship: '~zod', name: 'asdf' }, graph = {}) { this.graphAction({ 'add-graph': { resource, @@ -14,7 +14,7 @@ class PrivateHelper extends BaseApi { }); } - removeGraph(resource) { + removeGraph(resource = { ship: '~zod', name: 'asdf' }) { this.graphAction({ 'remove-graph': { resource @@ -22,7 +22,7 @@ class PrivateHelper extends BaseApi { }); } - addNodes(resource, nodes) { + addNodes(resource = { ship : '~zod', name: 'asdf' }, nodes = {}) { this.graphAction({ 'add-nodes': { resource, @@ -31,7 +31,7 @@ class PrivateHelper extends BaseApi { }); } - removeNodes(resource, indices) { + removeNodes(resource = { ship: '~zod', name: 'asdf' }, indices = []) { this.graphAction({ 'remove-nodes': { resource, @@ -55,6 +55,15 @@ class PrivateHelper extends BaseApi { removeTag() { this.graphAction(); } + + fetch(connection = 0) { + this.action('graph-view', 'graph-view-action', { + fetch: { + connection, + type: { all: null } + } + }); + } } export default class GraphApi { @@ -64,6 +73,7 @@ export default class GraphApi { this.ship = ship; this.subscribe = helper.subscribe.bind(helper); + // store this.addGraph = helper.addGraph.bind(helper); this.removeGraph = helper.removeGraph.bind(helper); @@ -75,6 +85,9 @@ export default class GraphApi { this.addTag = helper.addTag.bind(helper); this.removeTag = helper.removeTag.bind(helper); + + // view + this.fetch = helper.fetch.bind(helper); } } diff --git a/pkg/interface/src/subscription/graph.js b/pkg/interface/src/subscription/graph.js new file mode 100644 index 0000000000..2d242ac6b4 --- /dev/null +++ b/pkg/interface/src/subscription/graph.js @@ -0,0 +1,26 @@ +import BaseSubscription from './base'; + +let getRandomInt = (max) => { + return Math.floor(Math.random() * Math.floor(max)); +} + +export default class GraphSubscription extends BaseSubscription { + constructor(store, api, channel) { + super(store, api, channel); + this.connectionNumber = getRandomInt(999); + } + + start() { + this.subscribe('/updates/' + this.connectionNumber, 'graph-view'); + } + + handleEvent(diff) { + if ('graph-view' in diff) { + this.api.fetch(connectionNumber); + } else { + // extend + this.store.handleEvent(diff); + } + } +} + From 5b7a23ca30b7eac69720860b61f6e176716f7e2b Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 15:58:10 -0400 Subject: [PATCH 022/543] js: added minimal graph-store reducer --- pkg/interface/src/reducers/graph-update.js | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 pkg/interface/src/reducers/graph-update.js diff --git a/pkg/interface/src/reducers/graph-update.js b/pkg/interface/src/reducers/graph-update.js new file mode 100644 index 0000000000..ee1156399b --- /dev/null +++ b/pkg/interface/src/reducers/graph-update.js @@ -0,0 +1,43 @@ +import _ from 'lodash'; + +export default class GraphReducer { + reduce(json, state) { + const data = _.get(json, 'graph-update', false); + if (data) { + this.keys(data, state); + this.addGraph(data, state); + } + } + + keys(json, state) { + const data = _.get(json, 'keys', false); + if (data) { + state.keys = data.map((res) => { + return res.ship + '/' + res.name; + }); + } + } + + addGraph(json, state) { + const data = _.get(json, 'add-graph', false); + if (data) { + if (!('graphs' in state)) { + state.graphs = {}; + } + let resource = data.resource.ship + '/' + data.resource.name; + state.graphs[resource] = data.graph; + } + } + + removeGraph(json, state) { + const data = _.get(json, 'remove-graph', false); + if (data) { + if (!('graphs' in state)) { + state.graphs = {}; + } + let resource = data.resource.ship + '/' + data.resource.name; + delete state.graphs[resource]; + } + } + +} From dd75717871a8358dfa6a538dcf36ffbe4c1687a3 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 12 Jun 2020 16:28:57 -0400 Subject: [PATCH 023/543] js: tore apart graph-chat to simplify it for demo --- pkg/interface/src/App.js | 4 +- pkg/interface/src/api/graph.js | 8 +- pkg/interface/src/apps/graph-chat/app.js | 134 ++++++ .../src/apps/graph-chat/components/chat.js | 122 +++++ .../graph-chat/components/lib/channel-item.js | 37 ++ .../graph-chat/components/lib/chat-input.js | 293 ++++++++++++ .../graph-chat/components/lib/chat-tabbar.js | 12 + .../apps/graph-chat/components/lib/message.js | 255 ++++++++++ .../components/lib/overlay-sigil.js | 27 ++ .../src/apps/graph-chat/components/new.js | 92 ++++ .../src/apps/graph-chat/components/sidebar.js | 56 +++ .../apps/graph-chat/components/skeleton.js | 73 +++ .../src/apps/graph-chat/css/custom.css | 442 ++++++++++++++++++ pkg/interface/src/reducers/invite-update.js | 2 - pkg/interface/src/reducers/metadata-update.js | 2 - pkg/interface/src/store/graph.js | 24 + pkg/interface/src/subscription/graph.js | 6 +- 17 files changed, 1579 insertions(+), 10 deletions(-) create mode 100644 pkg/interface/src/apps/graph-chat/app.js create mode 100644 pkg/interface/src/apps/graph-chat/components/chat.js create mode 100644 pkg/interface/src/apps/graph-chat/components/lib/channel-item.js create mode 100644 pkg/interface/src/apps/graph-chat/components/lib/chat-input.js create mode 100644 pkg/interface/src/apps/graph-chat/components/lib/chat-tabbar.js create mode 100644 pkg/interface/src/apps/graph-chat/components/lib/message.js create mode 100644 pkg/interface/src/apps/graph-chat/components/lib/overlay-sigil.js create mode 100644 pkg/interface/src/apps/graph-chat/components/new.js create mode 100644 pkg/interface/src/apps/graph-chat/components/sidebar.js create mode 100644 pkg/interface/src/apps/graph-chat/components/skeleton.js create mode 100644 pkg/interface/src/apps/graph-chat/css/custom.css create mode 100644 pkg/interface/src/store/graph.js diff --git a/pkg/interface/src/App.js b/pkg/interface/src/App.js index e763554dcd..5b481df2f3 100644 --- a/pkg/interface/src/App.js +++ b/pkg/interface/src/App.js @@ -6,7 +6,7 @@ import './css/fonts.css'; import { light } from '@tlon/indigo-react'; import LaunchApp from './apps/launch/app'; -import ChatApp from './apps/chat/app'; +import GraphChatApp from './apps/graph-chat/app'; import DojoApp from './apps/dojo/app'; import GroupsApp from './apps/groups/app'; import LinksApp from './apps/links/app'; @@ -91,7 +91,7 @@ export default class App extends React.Component { )} /> ( - {}); + this.resetControllers(); + } + + render() { + const { state, props } = this; + + const renderChannelSidebar = (props, resource) => ( + + ); + + return ( +
+ { + return ( + +
+
+

+ Select, create, or join a chat to begin. +

+
+
+
+ ); + }} + /> + { + return ( + + + + ); + }} + /> + { + let resource = + `/${props.match.params.ship}/${props.match.params.name}`; + const graph = state.graphs[resource] || {}; + + return ( + + + + ); + }} + /> +
+ ); + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/chat.js b/pkg/interface/src/apps/graph-chat/components/chat.js new file mode 100644 index 0000000000..dffe7f918e --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/chat.js @@ -0,0 +1,122 @@ +import React, { Component } from 'react'; +import _ from 'lodash'; +import moment from 'moment'; + +import { Link } from 'react-router-dom'; + +import { Message } from './lib/message'; +import { ChatTabBar } from './lib/chat-tabbar'; +import { ChatInput } from './lib/chat-input'; +import { deSig } from '../../../lib/util'; + +export class ChatScreen extends Component { + constructor(props) { + super(props); + + this.state = { + }; + + moment.updateLocale('en', { + calendar: { + sameDay: '[Today]', + nextDay: '[Tomorrow]', + nextWeek: 'dddd', + lastDay: '[Yesterday]', + lastWeek: '[Last] dddd', + sameElse: 'DD/MM/YYYY' + } + }); + } + + chatWindow() { + const { props, state } = this; + + let messages = props.envelopes.slice(0); + + const messageElements = messages.map((msg, i) => { + // Render sigil if previous message is not by the same sender + const aut = ['author']; + const renderSigil = + _.get(messages[i + 1], aut) !== + _.get(msg, aut, msg.author); + const paddingTop = renderSigil; + const paddingBot = + _.get(messages[i - 1], aut) !== + _.get(msg, aut, msg.author); + + return ( + + ); + + }); + + return ( +
+
{ + this.scrollElement = el; + }} + >
+ {messageElements} +
+ ); + } + + render() { + const { props, state } = this; + + let title = props.resource.substr(1); + + return ( +
+
+ {'⟵ All Chats'} +
+
+ +

+ {title} +

+ + +
+ {this.chatWindow()} + +
+ ); + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/lib/channel-item.js b/pkg/interface/src/apps/graph-chat/components/lib/channel-item.js new file mode 100644 index 0000000000..8995fca1c8 --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/lib/channel-item.js @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; + +export class ChannelItem extends Component { + constructor(props) { + super(props); + } + + onClick() { + const { props } = this; + props.history.push('/~chat/room' + props.box); + } + + render() { + const { props } = this; + + const unreadElem = props.unread ? 'fw6' : ''; + + const title = props.title; + + const selectedCss = props.selected + ? 'bg-gray4 bg-gray1-d gray3-d c-default' + : 'bg-white bg-gray0-d gray3-d hover-bg-gray5 hover-bg-gray1-d pointer'; + + return ( +
+
+

+ {title} +

+
+
+ ); + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/lib/chat-input.js b/pkg/interface/src/apps/graph-chat/components/lib/chat-input.js new file mode 100644 index 0000000000..da28a35912 --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/lib/chat-input.js @@ -0,0 +1,293 @@ +import React, { Component } from 'react'; +import _ from 'lodash'; +import moment from 'moment'; +import { UnControlled as CodeEditor } from 'react-codemirror2'; +import CodeMirror from 'codemirror'; + +import 'codemirror/mode/markdown/markdown'; +import 'codemirror/addon/display/placeholder'; + +import 'codemirror/lib/codemirror.css'; + +import { Sigil } from '../../../../lib/sigil'; + +import { uxToHex } from '../../../../lib/util'; + +const MARKDOWN_CONFIG = { + name: 'markdown', + tokenTypeOverrides: { + header: 'presentation', + quote: 'presentation', + list1: 'presentation', + list2: 'presentation', + list3: 'presentation', + hr: 'presentation', + image: 'presentation', + imageAltText: 'presentation', + imageMarker: 'presentation', + formatting: 'presentation', + linkInline: 'presentation', + linkEmail: 'presentation', + linkText: 'presentation', + linkHref: 'presentation' + } +}; + +export class ChatInput extends Component { + constructor(props) { + super(props); + + this.state = { + message: '', + }; + + this.textareaRef = React.createRef(); + + this.messageSubmit = this.messageSubmit.bind(this); + this.messageChange = this.messageChange.bind(this); + + this.completePatp = this.completePatp.bind(this); + this.clearSearch = this.clearSearch.bind(this); + + this.toggleCode = this.toggleCode.bind(this); + + this.editor = null; + + // perf testing: + /* let closure = () => { + let x = 0; + for (var i = 0; i < 30; i++) { + x++; + props.api.chat.message( + props.resource, + `~${window.ship}`, + Date.now(), + { + text: `${x}` + } + ); + } + setTimeout(closure, 1000); + }; + this.closure = closure.bind(this);*/ + + moment.updateLocale('en', { + relativeTime : { + past: function(input) { + return input === 'just now' + ? input + : input + ' ago'; + }, + s : 'just now', + future: 'in %s', + ss : '%d sec', + m: 'a minute', + mm: '%d min', + h: 'an hr', + hh: '%d hrs', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years' + } + }); + } + + getLetterType(letter) { + if (letter.startsWith('/me ')) { + letter = letter.slice(4); + // remove insignificant leading whitespace. + // aces might be relevant to style. + while (letter[0] === '\n') { + letter = letter.slice(1); + } + + return { + me: letter + }; + } else if (this.isUrl(letter)) { + return { + url: letter + }; + } else { + return { + text: letter + }; + } + } + + isUrl(string) { + try { + const websiteTest = new RegExp(String(/^((\w+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+)/.source) + ); + return websiteTest.test(string); + } catch (e) { + return false; + } + } + + messageSubmit() { + if(!this.editor) { + return; + } + const { props, state } = this; + const editorMessage = this.editor.getValue(); + + if (editorMessage === '') { + return; + } + + if(state.code) { + props.api.chat.message(props.resource, `~${window.ship}`, Date.now(), { + code: { + expression: editorMessage, + output: undefined + } + }); + this.editor.setValue(''); + return; + } + let message = []; + editorMessage.split(' ').map((each) => { + if (this.isUrl(each)) { + if (message.length > 0) { + message = message.join(' '); + message = this.getLetterType(message); + props.api.chat.message( + props.resource, + `~${window.ship}`, + Date.now(), + message + ); + message = []; + } + const URL = this.getLetterType(each); + props.api.chat.message( + props.resource, + `~${window.ship}`, + Date.now(), + URL + ); + } else { + return message.push(each); + } + }); + + if (message.length > 0) { + message = message.join(' '); + message = this.getLetterType(message); + props.api.chat.message( + props.resource, + `~${window.ship}`, + Date.now(), + message + ); + message = []; + } + + // perf: + // setTimeout(this.closure, 2000); + + this.editor.setValue(''); + } + + toggleCode() { + if(this.state.code) { + this.setState({ code: false }); + this.editor.setOption('mode', MARKDOWN_CONFIG); + this.editor.setOption('placeholder', this.props.placeholder); + } else { + this.setState({ code: true }); + this.editor.setOption('mode', null); + this.editor.setOption('placeholder', 'Code...'); + } + const value = this.editor.getValue(); + + // Force redraw of placeholder + if(value.length === 0) { + this.editor.setValue(' '); + this.editor.setValue(''); + } + } + + render() { + const { props, state } = this; + + + const codeTheme = state.code ? ' code' : ''; + + const options = { + mode: MARKDOWN_CONFIG, + theme: 'tlon' + codeTheme, + lineNumbers: false, + lineWrapping: true, + scrollbarStyle: 'native', + cursorHeight: 0.85, + placeholder: state.code ? 'Code...' : props.placeholder, + extraKeys: { + 'Enter': () => { + this.messageSubmit(); + if (this.state.code) { + this.toggleCode(); + } + }, + 'Shift-3': cm => + cm.getValue().length === 0 + ? this.toggleCode() + : CodeMirror.Pass + } + }; + + return ( +
+
+ +
+
+ { + this.editor = editor; + if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test( + navigator.userAgent + )) { + editor.focus(); + } + }} + onChange={(e, d, v) => this.messageChange(e, d, v)} + /> +
+
+
+
+ +
+
+ ); + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/lib/chat-tabbar.js b/pkg/interface/src/apps/graph-chat/components/lib/chat-tabbar.js new file mode 100644 index 0000000000..120d60e850 --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/lib/chat-tabbar.js @@ -0,0 +1,12 @@ +import React, { Component } from 'react'; +import { Link } from 'react-router-dom'; + +export class ChatTabBar extends Component { + render() { + const props = this.props; + return ( +
+
+ ); + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/lib/message.js b/pkg/interface/src/apps/graph-chat/components/lib/message.js new file mode 100644 index 0000000000..3c71544f43 --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/lib/message.js @@ -0,0 +1,255 @@ +import React, { Component } from 'react'; +import { OverlaySigil } from './overlay-sigil'; +import { uxToHex, cite, writeText } from '../../../../lib/util'; +import moment from 'moment'; +import ReactMarkdown from 'react-markdown'; +import RemarkDisableTokenizers from 'remark-disable-tokenizers'; + +const DISABLED_BLOCK_TOKENS = [ + 'indentedCode', + 'blockquote', + 'atxHeading', + 'thematicBreak', + 'list', + 'setextHeading', + 'html', + 'definition', + 'table' +]; + +const DISABLED_INLINE_TOKENS = [ + 'autoLink', + 'url', + 'email', + 'link', + 'reference' +]; + +const MessageMarkdown = React.memo( + props => ()); + +export class Message extends Component { + constructor() { + super(); + this.state = { + unfold: false, + copied: false + }; + this.unFoldEmbed = this.unFoldEmbed.bind(this); + } + + unFoldEmbed(id) { + let unfoldState = this.state.unfold; + unfoldState = !unfoldState; + this.setState({ unfold: unfoldState }); + const iframe = this.refs.iframe; + iframe.setAttribute('src', iframe.getAttribute('data-src')); + } + + renderContent() { + const { props } = this; + const letter = props.msg.letter; + + if ('code' in letter) { + const outputElement = + (Boolean(letter.code.output) && + letter.code.output.length && letter.code.output.length > 0) ? + ( +
+            {letter.code.output[0].join('\n')}
+          
+ ) : null; + return ( +
+
+            {letter.code.expression}
+          
+ {outputElement} +
+ ); + } else if ('url' in letter) { + let imgMatch = + /(jpg|img|png|gif|tiff|jpeg|JPG|IMG|PNG|TIFF|GIF|webp|WEBP|webm|WEBM|svg|SVG)$/ + .exec(letter.url); + const youTubeRegex = new RegExp(String(/(?:https?:\/\/(?:[a-z]+.)?)/.source) // protocol + + /(?:youtu\.?be(?:\.com)?\/)(?:embed\/)?/.source // short and long-links + + /(?:(?:(?:(?:watch\?)?(?:time_continue=(?:[0-9]+))?.+v=)?([a-zA-Z0-9_-]+))(?:\?t\=(?:[0-9a-zA-Z]+))?)/.source // id + ); + const ytMatch = + youTubeRegex.exec(letter.url); + let contents = letter.url; + if (imgMatch) { + contents = ( + + ); + return ( + + {contents} + + ); + } else if (ytMatch) { + contents = ( +
+ +
+ ); + return ( + + ); + } else { + return ( + + {contents} + + ); + } + } else if ('me' in letter) { + return ( +

+ {letter.me} +

+ ); + } else { + return ( +
+ +
+ ); + } + } + + render() { + const { props, state } = this; + const pending = props.msg.pending ? ' o-40' : ''; + const datestamp = '~' + moment.unix(props.msg.when / 1000).format('YYYY.M.D'); + + const paddingTop = props.paddingTop ? { 'paddingTop': '6px' } : ''; + + if (props.renderSigil) { + const timestamp = moment.unix(props.msg.when / 1000).format('hh:mm a'); + + const contact = props.msg.author in props.contacts + ? props.contacts[props.msg.author] : false; + let name = `~${props.msg.author}`; + let color = '#000000'; + let sigilClass = 'mix-blend-diff'; + if (contact) { + name = (contact.nickname.length > 0) + ? contact.nickname : `~${props.msg.author}`; + color = `#${uxToHex(contact.color)}`; + sigilClass = ''; + } + + if (`~${props.msg.author}` === name) { + name = cite(props.msg.author); + } + + return ( +
+ +
+
+

+ { + writeText(props.msg.author); + this.setState({ copied: true }); + setTimeout(() => { + this.setState({ copied: false }); + }, 800); + }} + title={`~${props.msg.author}`} + > + {state.copied && 'Copied' || name} + +

+

{timestamp}

+

{datestamp}

+
+ {this.renderContent()} +
+
+ ); + } else { + const timestamp = moment.unix(props.msg.when / 1000).format('hh:mm'); + + return ( +
+

{timestamp}

+
+ {this.renderContent()} +
+
+ ); + } + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/lib/overlay-sigil.js b/pkg/interface/src/apps/graph-chat/components/lib/overlay-sigil.js new file mode 100644 index 0000000000..551643936c --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/lib/overlay-sigil.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react'; +import { Sigil } from '../../../../lib/sigil'; + +export class OverlaySigil extends Component { + constructor() { + super(); + } + + render() { + const { props, state } = this; + + return ( +
+ + +
+ ); + } +} diff --git a/pkg/interface/src/apps/graph-chat/components/new.js b/pkg/interface/src/apps/graph-chat/components/new.js new file mode 100644 index 0000000000..aef8b2fd95 --- /dev/null +++ b/pkg/interface/src/apps/graph-chat/components/new.js @@ -0,0 +1,92 @@ +import React, { Component } from 'react'; +import { Spinner } from '../../../components/Spinner'; +import { Link } from 'react-router-dom'; +import { deSig } from '../../../lib/util'; +import urbitOb from 'urbit-ob'; + + +export class NewScreen extends Component { + constructor(props) { + super(props); + this.state = { + title: '', + awaiting: false + }; + + this.titleChange = this.titleChange.bind(this); + } + + componentDidUpdate(prevProps, prevState) { + const { props, state } = this; + + if (prevProps !== props) { + const resource = `~${window.ship}/${state.idName}`; + if (resource in props.graphs) { + props.history.push('/~chat/room/' + resource); + } + } + } + + titleChange(event) { + const asciiSafe = event.target.value.toLowerCase() + .replace(/[^a-z0-9~_.-]/g, '-'); + this.setState({ + idName: asciiSafe, + title: event.target.value + }); + } + + onClickCreate() { + const { props, state } = this; + + this.setState({ + awaiting: true + }, () => { + props.api.addGraph(`~${window.ship}`, state.title, {}); + }); + } + + render() { + const { props, state } = this; + const createClasses = state.idName + ? 'pointer db f9 green2 bg-gray0-d ba pv3 ph4 b--green2' + : 'pointer db f9 gray2 ba bg-gray0-d pa2 pv3 ph4 b--gray3'; + + const idClasses = + 'f7 ba b--gray3 b--gray2-d bg-gray0-d white-d pa3 db w-100 ' + + 'focus-b--black focus-b--white-d '; + + return ( +
+
+ {'⟵ All Chats'} +
+

New Chat

+
+

Name

+ -)); - -CommentInput.displayName = 'commentInput'; - -export default CommentInput; diff --git a/pkg/interface/src/apps/publish/components/lib/comment-item.js b/pkg/interface/src/apps/publish/components/lib/comment-item.js deleted file mode 100644 index 4c64969fd7..0000000000 --- a/pkg/interface/src/apps/publish/components/lib/comment-item.js +++ /dev/null @@ -1,155 +0,0 @@ -import React, { Component } from 'react'; -import moment from 'moment'; -import { Sigil } from '../../../../lib/sigil'; -import CommentInput from './comment-input'; -import { uxToHex, cite } from '../../../../lib/util'; - -export class CommentItem extends Component { - constructor(props) { - super(props); - - this.state = { - commentBody: '' - }; - - this.commentChange = this.commentChange.bind(this); - this.commentEdit = this.commentEdit.bind(this); - moment.updateLocale('en', { - relativeTime: { - past: function(input) { - return input === 'just now' - ? input - : input + ' ago'; - }, - s : 'just now', - future : 'in %s', - m : '1m', - mm : '%dm', - h : '1h', - hh : '%dh', - d : '1d', - dd : '%dd', - M : '1 month', - MM : '%d months', - y : '1 year', - yy : '%d years' - } - }); - } - - commentEdit() { - const commentPath = Object.keys(this.props.comment)[0]; - const commentBody = this.props.comment[commentPath].content; - this.setState({ commentBody }); - this.props.onEdit(); - } - - focusTextArea(text) { - text && text.focus(); - } - - commentChange(e) { - this.setState({ - commentBody: e.target.value - }); - } - - onUpdate() { - this.props.onUpdate(this.state.commentBody); - } - - render() { - const pending = this.props.pending ? 'o-60' : ''; - const commentData = this.props.comment[Object.keys(this.props.comment)[0]]; - const content = commentData.content.split('\n').map((line, i) => { - return ( -

{line}

- ); - }); - const date = moment(commentData['date-created']).fromNow(); - - const contact = commentData.author.substr(1) in this.props.contacts - ? this.props.contacts[commentData.author.substr(1)] : false; - - let name = commentData.author; - let color = '#000000'; - let classes = 'mix-blend-diff'; - let avatar = null; - if (contact) { - name = (contact.nickname.length > 0) - ? contact.nickname : commentData.author; - color = `#${uxToHex(contact.color)}`; - classes = ''; - avatar = contact.avatar; - } - - const img = (avatar !== null) - ? - : ; - - if (name === commentData.author) { - name = cite(commentData.author); - } - - const { editing } = this.props; - - const disabled = this.props.pending - || window.ship !== commentData.author.slice(1); - - return ( -
-
- {img} -
- {name} -
-
{date}
- { !editing && !disabled && ( - <> -
- Edit -
-
- Delete -
- - ) } -
-
- { !editing && content } - { editing && ( - { - this.focusTextArea(el); - }} - onChange={this.commentChange} - value={this.state.commentBody} - onSubmit={this.onUpdate.bind(this)} - > - - )} -
- { editing && ( -
-
- Submit -
-
- Cancel -
-
- )} -
- ); - } -} - -export default CommentItem; diff --git a/pkg/interface/src/apps/publish/components/lib/comments.js b/pkg/interface/src/apps/publish/components/lib/comments.js deleted file mode 100644 index 32fdca68cc..0000000000 --- a/pkg/interface/src/apps/publish/components/lib/comments.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, { Component } from 'react'; -import { CommentItem } from './comment-item'; -import CommentInput from './comment-input'; -import { dateToDa } from '../../../../lib/util'; -import { Spinner } from '../../../../components/Spinner'; - -export class Comments extends Component { - constructor(props) { - super(props); - this.state = { - commentBody: '', - pending: new Set(), - awaiting: null, - editing: null - }; - this.commentSubmit = this.commentSubmit.bind(this); - this.commentChange = this.commentChange.bind(this); - } - - componentDidUpdate(prevProps) { - const previousComments = prevProps.comments[0] || {}; - const currentComments = this.props.comments[0] || {}; - const previous = Object.keys(previousComments) || []; - const current = Object.keys(currentComments) || []; - if ((prevProps.comments && this.props.comments) && - (previous !== current)) { - const pendingSet = this.state.pending; - Object.keys(currentComments).map((com) => { - const obj = currentComments[com]; - for (const each of pendingSet.values()) { - if (obj.content === each['new-comment'].body) { - pendingSet.delete(each); - this.setState({ pending: pendingSet }); - } - } - }); - } - } - - commentSubmit(evt) { - const comment = { - 'new-comment': { - who: this.props.ship.slice(1), - book: this.props.book, - note: this.props.note, - body: this.state.commentBody - } - }; - - const pendingState = this.state.pending; - pendingState.add(comment); - this.setState({ pending: pendingState }); - - this.textArea.value = ''; - this.setState({ commentBody: '', awaiting: 'new' }); - const submit = this.props.api.publish.publishAction(comment); - submit.then(() => { - this.setState({ awaiting: null }); - }); - } - - commentChange(evt) { - this.setState({ - commentBody: evt.target.value - }); - } - - commentEdit(idx) { - this.setState({ editing: idx }); - } - - commentEditCancel() { - this.setState({ editing: null }); - } - - commentUpdate(idx, body) { - const path = Object.keys(this.props.comments[idx])[0]; - const comment = { - 'edit-comment': { - who: this.props.ship.slice(1), - book: this.props.book, - note: this.props.note, - body: body, - comment: path - } - }; - - this.setState({ awaiting: 'edit' }); - - this.props.api.publish - .publishAction(comment) - .then(() => { - this.setState({ awaiting: null, editing: null }); - }); - } - - commentDelete(idx) { - const path = Object.keys(this.props.comments[idx])[0]; - const comment = { - 'del-comment': { - who: this.props.ship.slice(1), - book: this.props.book, - note: this.props.note, - comment: path - } - }; - - this.setState({ awaiting: { kind: 'del', what: idx } }); - this.props.api.publish - .publishAction(comment) - .then(() => { - this.setState({ awaiting: null }); -}); - } - - render() { - if (!this.props.enabled) { - return null; - } - - const { editing } = this.state; - - const pendingArray = Array.from(this.state.pending).map((com, i) => { - const da = dateToDa(new Date()); - const comment = { - [da]: { - author: `~${window.ship}`, - content: com['new-comment'].body, - 'date-created': Math.round(new Date().getTime()) - } - }; - return ( - - ); - }); - - const commentArray = this.props.comments.map((com, i) => { - return ( - this.commentUpdate(i, u)} - onDelete={() => this.commentDelete(i)} - onEdit={() => this.commentEdit(i)} - onEditCancel={this.commentEditCancel.bind(this)} - editing={i === editing} - disabled={Boolean(this.state.awaiting) || editing} - /> - ); - }); - - const disableComment = ((this.state.commentBody === '') || (Boolean(this.state.awaiting))); - const commentClass = (disableComment) - ? 'bg-transparent f9 pa2 br1 ba b--gray2 gray2' - : 'bg-transparent f9 pa2 br1 ba b--gray2 black white-d pointer'; - - const spinnerText = - this.state.awaiting === 'new' - ? 'Posting commment...' - : this.state.awaiting === 'edit' - ? 'Updating comment...' - : 'Deleting comment...'; - - return ( -
-
-
- { - this.textArea = el; - }} - onChange={this.commentChange} - value={this.state.commentBody} - disabled={Boolean(this.state.editing)} - onSubmit={this.commentSubmit} - > - -
- - -
- {pendingArray} - {commentArray} -
- ); - } -} - -export default Comments; diff --git a/pkg/interface/src/apps/publish/components/lib/dropdown.js b/pkg/interface/src/apps/publish/components/lib/dropdown.js deleted file mode 100644 index 7f08bc3ab4..0000000000 --- a/pkg/interface/src/apps/publish/components/lib/dropdown.js +++ /dev/null @@ -1,89 +0,0 @@ -import React, { Component } from 'react'; - -export class Dropdown extends Component { - constructor(props) { - super(props); - - this.toggleDropdown = this.toggleDropdown.bind(this); - this.handleClickOutside = this.handleClickOutside.bind(this); - this.collapseAndDispatch = this.collapseAndDispatch.bind(this); - this.state = { - open: false - }; - } - - componentDidMount() { - document.addEventListener('mousedown', this.handleClickOutside); - } - - componentWillUnmount() { - document.removeEventListener('mousedown', this.handleClickOutside); - } - - handleClickOutside(evt) { - if (this.optsList && !this.optsList.contains(evt.target) && - this.optsButton && !this.optsButton.contains(evt.target)) { - this.setState({ open: false }); - } - } - - toggleDropdown() { - this.setState({ open: !this.state.open }); - } - - collapseAndDispatch(action) { - this.setState({ open: false }, action); - } - - render() { - const alignment = (this.props.align) - ? this.props.align : 'right'; - - const display = (this.state.open) - ? 'block' : 'none'; - - const optionsClass = (this.state.open) - ? 'open' : 'closed'; - - let leftAlign = ''; - let rightAlign = '0'; - - if (alignment === 'left') { - leftAlign = '0'; - rightAlign = ''; - } - - const optionsList = this.props.options.map((val, i) => { - return ( - - ); - }); - - return ( -
{ - this.optsButton = el; - }} - onClick={this.toggleDropdown} - > - -
{ - this.optsList = el; - }} - style={{ left: leftAlign, right: rightAlign, width:this.props.width, display: display }} - > - {optionsList} -
-
- ); - } -} - -export default Dropdown; diff --git a/pkg/interface/src/apps/publish/components/lib/join.js b/pkg/interface/src/apps/publish/components/lib/join.js deleted file mode 100644 index 3dfad2aa12..0000000000 --- a/pkg/interface/src/apps/publish/components/lib/join.js +++ /dev/null @@ -1,176 +0,0 @@ -import React, { Component } from 'react'; -import { Link } from 'react-router-dom'; -import { Spinner } from '../../../../components/Spinner'; -import urbitOb from 'urbit-ob'; - -export class JoinScreen extends Component { - constructor(props) { - super(props); - - this.state = { - book: '', - error: false, - awaiting: null, - disable: false - }; - - this.bookChange = this.bookChange.bind(this); - } - - componentDidMount() { - this.componentDidUpdate(); - } - - componentDidUpdate(prevProps) { - if ((this.props.ship) && (this.props.notebook)) { - const incomingBook = `${this.props.ship}/${this.props.notebook}`; - if (this.props.api && (prevProps?.api !== this.props.api)) { - this.setState({ book: incomingBook }, () => { - this.onClickJoin(); - }); - } - } - // redirect to notebook when we have it - if (this.props.notebooks) { - if (this.state.awaiting) { - const book = this.state.awaiting.split('/'); - const ship = book[0]; - const notebook = book[1]; - if ((ship in this.props.notebooks) && - (notebook in this.props.notebooks[ship])) { - this.setState({ disable: false, book: '/' }); - this.props.history.push(`/~publish/notebook/${ship}/${notebook}`); - } - } - } - } - - notebooksInclude(text, notebookObj) { - let verdict = false; - let keyPair = []; - // validate that it's a worthwhile thing to check - // certainly a unit would be nice here - if (text.indexOf('/') === -1) { - return verdict; - } else { - keyPair = text.split('/'); - }; - // check both levels of object - if (keyPair[0] in notebookObj) { - if (keyPair[1] in notebookObj[keyPair[0]]) { - verdict = true; - } - } - return verdict; - } - - onClickJoin() { - const { props, state } = this; - - const text = state.book; - - let book = text.split('/'); - const ship = book[0]; - book.splice(0, 1); - book = '/' + book.join('/'); - - if (this.notebooksInclude(state.book, props.notebooks)) { - const href = `/~publish/notebook/${ship}${book}`; - return props.history.push(href); - } - - if (book.length < 2 || !urbitOb.isValidPatp(ship)) { - this.setState({ - error: true - }); - return; - } - - const actionData = { - subscribe: { - who: ship.replace('~',''), - book: /\/?(.*)/.exec(book)[1] - } - }; - - // TODO: askHistory setting - this.setState({ disable: true }); - this.props.api.publish.publishAction(actionData).catch((err) => { - console.log(err); - }).then(() => { - this.setState({ awaiting: text }); - }); - } - - bookChange(event) { - this.setState({ - book: event.target.value - }); - } - - render() { - const { state } = this; - - let joinClasses = 'db f9 green2 ba pa2 b--green2 bg-gray0-d pointer'; - if ((state.disable) || (!state.book) || (state.book === '/')) { - joinClasses = 'db f9 gray2 ba pa2 b--gray3 bg-gray0-d'; - } - - let errElem = (); - if (state.error) { - errElem = ( - - Notebook must have a valid name. - - ); - } - - return ( -
-
- {'⟵ All Notebooks'} -
-

Subscribe to an Existing Notebook

-
-

Enter a ~ship/notebook-name

-

Notebook names use lowercase, hyphens, and slashes.

- -)); - -CommentInput.displayName = 'commentInput'; - -export default CommentInput; diff --git a/pkg/interface/src/views/apps/publish/components/lib/comment-item.js b/pkg/interface/src/views/apps/publish/components/lib/comment-item.js deleted file mode 100644 index dfd4b43ca7..0000000000 --- a/pkg/interface/src/views/apps/publish/components/lib/comment-item.js +++ /dev/null @@ -1,155 +0,0 @@ -import React, { Component } from 'react'; -import moment from 'moment'; -import { Sigil } from '~/logic/lib/sigil'; -import CommentInput from './comment-input'; -import { uxToHex, cite } from '~/logic/lib/util'; - -export class CommentItem extends Component { - constructor(props) { - super(props); - - this.state = { - commentBody: '' - }; - - this.commentChange = this.commentChange.bind(this); - this.commentEdit = this.commentEdit.bind(this); - moment.updateLocale('en', { - relativeTime: { - past: function(input) { - return input === 'just now' - ? input - : input + ' ago'; - }, - s : 'just now', - future : 'in %s', - m : '1m', - mm : '%dm', - h : '1h', - hh : '%dh', - d : '1d', - dd : '%dd', - M : '1 month', - MM : '%d months', - y : '1 year', - yy : '%d years' - } - }); - } - - commentEdit() { - const commentPath = Object.keys(this.props.comment)[0]; - const commentBody = this.props.comment[commentPath].content; - this.setState({ commentBody }); - this.props.onEdit(); - } - - focusTextArea(text) { - text && text.focus(); - } - - commentChange(e) { - this.setState({ - commentBody: e.target.value - }); - } - - onUpdate() { - this.props.onUpdate(this.state.commentBody); - } - - render() { - const pending = this.props.pending ? 'o-60' : ''; - const commentData = this.props.comment[Object.keys(this.props.comment)[0]]; - const content = commentData.content.split('\n').map((line, i) => { - return ( -

{line}

- ); - }); - const date = moment(commentData['date-created']).fromNow(); - - const contact = commentData.author.substr(1) in this.props.contacts - ? this.props.contacts[commentData.author.substr(1)] : false; - - let name = commentData.author; - let color = '#000000'; - let classes = 'mix-blend-diff'; - let avatar = null; - if (contact) { - name = (contact.nickname.length > 0) - ? contact.nickname : commentData.author; - color = `#${uxToHex(contact.color)}`; - classes = ''; - avatar = contact.avatar; - } - - const img = (avatar !== null) - ? - : ; - - if (name === commentData.author) { - name = cite(commentData.author); - } - - const { editing } = this.props; - - const disabled = this.props.pending - || window.ship !== commentData.author.slice(1); - - return ( -
-
- {img} -
- {name} -
-
{date}
- { !editing && !disabled && ( - <> -
- Edit -
-
- Delete -
- - ) } -
-
- { !editing && content } - { editing && ( - { - this.focusTextArea(el); - }} - onChange={this.commentChange} - value={this.state.commentBody} - onSubmit={this.onUpdate.bind(this)} - > - - )} -
- { editing && ( -
-
- Submit -
-
- Cancel -
-
- )} -
- ); - } -} - -export default CommentItem; diff --git a/pkg/interface/src/views/apps/publish/components/lib/comments.js b/pkg/interface/src/views/apps/publish/components/lib/comments.js deleted file mode 100644 index fbbe9011fc..0000000000 --- a/pkg/interface/src/views/apps/publish/components/lib/comments.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, { Component } from 'react'; -import { CommentItem } from './comment-item'; -import CommentInput from './comment-input'; -import { dateToDa } from '~/logic/lib/util'; -import { Spinner } from '~/views/components/Spinner'; - -export class Comments extends Component { - constructor(props) { - super(props); - this.state = { - commentBody: '', - pending: new Set(), - awaiting: null, - editing: null - }; - this.commentSubmit = this.commentSubmit.bind(this); - this.commentChange = this.commentChange.bind(this); - } - - componentDidUpdate(prevProps) { - const previousComments = prevProps.comments[0] || {}; - const currentComments = this.props.comments[0] || {}; - const previous = Object.keys(previousComments) || []; - const current = Object.keys(currentComments) || []; - if ((prevProps.comments && this.props.comments) && - (previous !== current)) { - const pendingSet = this.state.pending; - Object.keys(currentComments).map((com) => { - const obj = currentComments[com]; - for (const each of pendingSet.values()) { - if (obj.content === each['new-comment'].body) { - pendingSet.delete(each); - this.setState({ pending: pendingSet }); - } - } - }); - } - } - - commentSubmit(evt) { - const comment = { - 'new-comment': { - who: this.props.ship.slice(1), - book: this.props.book, - note: this.props.note, - body: this.state.commentBody - } - }; - - const pendingState = this.state.pending; - pendingState.add(comment); - this.setState({ pending: pendingState }); - - this.textArea.value = ''; - this.setState({ commentBody: '', awaiting: 'new' }); - const submit = this.props.api.publish.publishAction(comment); - submit.then(() => { - this.setState({ awaiting: null }); - }); - } - - commentChange(evt) { - this.setState({ - commentBody: evt.target.value - }); - } - - commentEdit(idx) { - this.setState({ editing: idx }); - } - - commentEditCancel() { - this.setState({ editing: null }); - } - - commentUpdate(idx, body) { - const path = Object.keys(this.props.comments[idx])[0]; - const comment = { - 'edit-comment': { - who: this.props.ship.slice(1), - book: this.props.book, - note: this.props.note, - body: body, - comment: path - } - }; - - this.setState({ awaiting: 'edit' }); - - this.props.api.publish - .publishAction(comment) - .then(() => { - this.setState({ awaiting: null, editing: null }); - }); - } - - commentDelete(idx) { - const path = Object.keys(this.props.comments[idx])[0]; - const comment = { - 'del-comment': { - who: this.props.ship.slice(1), - book: this.props.book, - note: this.props.note, - comment: path - } - }; - - this.setState({ awaiting: { kind: 'del', what: idx } }); - this.props.api.publish - .publishAction(comment) - .then(() => { - this.setState({ awaiting: null }); -}); - } - - render() { - if (!this.props.enabled) { - return null; - } - - const { editing } = this.state; - - const pendingArray = Array.from(this.state.pending).map((com, i) => { - const da = dateToDa(new Date()); - const comment = { - [da]: { - author: `~${window.ship}`, - content: com['new-comment'].body, - 'date-created': Math.round(new Date().getTime()) - } - }; - return ( - - ); - }); - - const commentArray = this.props.comments.map((com, i) => { - return ( - this.commentUpdate(i, u)} - onDelete={() => this.commentDelete(i)} - onEdit={() => this.commentEdit(i)} - onEditCancel={this.commentEditCancel.bind(this)} - editing={i === editing} - disabled={Boolean(this.state.awaiting) || editing} - /> - ); - }); - - const disableComment = ((this.state.commentBody === '') || (Boolean(this.state.awaiting))); - const commentClass = (disableComment) - ? 'bg-transparent f9 pa2 br1 ba b--gray2 gray2' - : 'bg-transparent f9 pa2 br1 ba b--gray2 black white-d pointer'; - - const spinnerText = - this.state.awaiting === 'new' - ? 'Posting commment...' - : this.state.awaiting === 'edit' - ? 'Updating comment...' - : 'Deleting comment...'; - - return ( -
-
-
- { - this.textArea = el; - }} - onChange={this.commentChange} - value={this.state.commentBody} - disabled={Boolean(this.state.editing)} - onSubmit={this.commentSubmit} - > - -
- - -
- {pendingArray} - {commentArray} -
- ); - } -} - -export default Comments; diff --git a/pkg/interface/src/views/apps/publish/components/lib/dropdown.js b/pkg/interface/src/views/apps/publish/components/lib/dropdown.js deleted file mode 100644 index 7f08bc3ab4..0000000000 --- a/pkg/interface/src/views/apps/publish/components/lib/dropdown.js +++ /dev/null @@ -1,89 +0,0 @@ -import React, { Component } from 'react'; - -export class Dropdown extends Component { - constructor(props) { - super(props); - - this.toggleDropdown = this.toggleDropdown.bind(this); - this.handleClickOutside = this.handleClickOutside.bind(this); - this.collapseAndDispatch = this.collapseAndDispatch.bind(this); - this.state = { - open: false - }; - } - - componentDidMount() { - document.addEventListener('mousedown', this.handleClickOutside); - } - - componentWillUnmount() { - document.removeEventListener('mousedown', this.handleClickOutside); - } - - handleClickOutside(evt) { - if (this.optsList && !this.optsList.contains(evt.target) && - this.optsButton && !this.optsButton.contains(evt.target)) { - this.setState({ open: false }); - } - } - - toggleDropdown() { - this.setState({ open: !this.state.open }); - } - - collapseAndDispatch(action) { - this.setState({ open: false }, action); - } - - render() { - const alignment = (this.props.align) - ? this.props.align : 'right'; - - const display = (this.state.open) - ? 'block' : 'none'; - - const optionsClass = (this.state.open) - ? 'open' : 'closed'; - - let leftAlign = ''; - let rightAlign = '0'; - - if (alignment === 'left') { - leftAlign = '0'; - rightAlign = ''; - } - - const optionsList = this.props.options.map((val, i) => { - return ( - - ); - }); - - return ( -
{ - this.optsButton = el; - }} - onClick={this.toggleDropdown} - > - -
{ - this.optsList = el; - }} - style={{ left: leftAlign, right: rightAlign, width:this.props.width, display: display }} - > - {optionsList} -
-
- ); - } -} - -export default Dropdown; diff --git a/pkg/interface/src/views/apps/publish/components/lib/edit-post.js b/pkg/interface/src/views/apps/publish/components/lib/edit-post.js deleted file mode 100644 index a259bbda31..0000000000 --- a/pkg/interface/src/views/apps/publish/components/lib/edit-post.js +++ /dev/null @@ -1,145 +0,0 @@ -import React, { Component } from 'react'; -import { SidebarSwitcher } from '~/views/components/SidebarSwitch'; -import { Spinner } from '~/views/components/Spinner'; -import { Link } from 'react-router-dom'; -import { Controlled as CodeMirror } from 'react-codemirror2'; -import { dateToDa } from '~/logic/lib/util'; - -import 'codemirror/mode/markdown/markdown'; - -export class EditPost extends Component { - constructor(props) { - super(props); - this.state = { - body: '', - submit: false, - awaiting: false - }; - this.postSubmit = this.postSubmit.bind(this); - this.bodyChange = this.bodyChange.bind(this); - } - - componentDidMount() { - this.componentDidUpdate(); - } - - componentDidUpdate(prevProps) { - const { props, state } = this; - const contents = props.notebooks[props.ship]?.[props.book]?.notes?.[props.note]?.file; - if (prevProps && prevProps.api !== props.api) { - if (!contents) { - props.api?.fetchNote(props.ship, props.book, props.note); - } - } - if (contents && state.body === '') { - const notebook = props.notebooks[props.ship][props.book]; - const note = notebook.notes[props.note]; - const file = note.file; - const body = file.slice(file.indexOf(';>') + 3); - this.setState({ body: body }); - } - } - - postSubmit() { - const { props, state } = this; - const notebook = props.notebooks[props.ship][props.book]; - const note = notebook.notes[props.note]; - const title = note.title; - const editNote = { - 'edit-note': { - who: props.ship.slice(1), - book: props.book, - note: props.note, - title: title, - body: state.body - } - }; - this.setState({ awaiting: true }); - this.props.api.publish.publishAction(editNote).then(() => { - const editIndex = props.location.pathname.indexOf('/edit'); - const noteHref = props.location.pathname.slice(0, editIndex); - this.setState({ awaiting: false }); - props.history.push(noteHref); - }); - } - - bodyChange(editor, data, value) { - const submit = !(value === ''); - this.setState({ body: value, submit: submit }); - } - - render() { - const { props, state } = this; - const notebook = props.notebooks[props.ship][props.book]; - const note = notebook.notes[props.note]; - const title = note.title; - let date = dateToDa(new Date(note['date-created'])); - date = date.slice(1, -10); - - const submitStyle = (state.submit) - ? { color: '#2AA779', cursor: 'pointer' } - : { color: '#B1B2B3', cursor: 'auto' }; - - const hrefIndex = props.location.pathname.indexOf('/note/'); - const publishsubStr = props.location.pathname.substr(hrefIndex); - const popoutHref = `/~publish/popout${publishsubStr}`; - - const hiddenOnPopout = (props.popout) - ? '' : 'dib-m dib-l dib-xl'; - - const options = { - mode: 'markdown', - theme: 'tlon', - lineNumbers: false, - lineWrapping: true, - scrollbarStyle: null, - cursorHeight: 0.85 - }; - - return ( -
-
- - - - - -
-
-
-
{date}
-
-
- this.bodyChange(e, d, v)} - onChange={(editor, data, value) => {}} - /> - -
-
-
- ); - } -} - -export default EditPost; diff --git a/pkg/interface/src/views/apps/publish/components/lib/group-item.js b/pkg/interface/src/views/apps/publish/components/lib/group-item.js deleted file mode 100644 index dd5ffb731c..0000000000 --- a/pkg/interface/src/views/apps/publish/components/lib/group-item.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { Component } from 'react'; -import { Box, Text } from "@tlon/indigo-react"; -import { NotebookItem } from './NotebookItem'; - -export class GroupItem extends Component { - render() { - const { props } = this; - const association = props.association ? props.association : {}; - - let title = association['app-path'] ? association['app-path'] : 'Unmanaged Notebooks'; - if (association.metadata && association.metadata.title) { - title = association.metadata.title !== '' - ? association.metadata.title : title; - } - - const groupedBooks = props.groupedBooks ? props.groupedBooks : []; - const first = (props.index === 0) ? 'pt1' : 'pt6'; - - const notebookItems = groupedBooks.map((each, i) => { - const unreads = props.notebooks[each]['num-unread'] || 0; - let title = each.substr(1); - if (props.notebooks[each].title) { - title = (props.notebooks[each].title !== '') - ? props.notebooks[each].title : title; - } - return ( - - ); - }); - return ( - - {title} - {notebookItems} - - ); - } -} - -export default GroupItem; diff --git a/pkg/interface/src/views/apps/publish/components/lib/join.js b/pkg/interface/src/views/apps/publish/components/lib/join.js deleted file mode 100644 index 0269c5d51b..0000000000 --- a/pkg/interface/src/views/apps/publish/components/lib/join.js +++ /dev/null @@ -1,176 +0,0 @@ -import React, { Component } from 'react'; -import { Link } from 'react-router-dom'; -import { Spinner } from '~/views/components/Spinner'; -import urbitOb from 'urbit-ob'; - -export class JoinScreen extends Component { - constructor(props) { - super(props); - - this.state = { - book: '', - error: false, - awaiting: null, - disable: false - }; - - this.bookChange = this.bookChange.bind(this); - } - - componentDidMount() { - this.componentDidUpdate(); - } - - componentDidUpdate(prevProps) { - if ((this.props.ship) && (this.props.notebook)) { - const incomingBook = `${this.props.ship}/${this.props.notebook}`; - if (this.props.api && (prevProps?.api !== this.props.api)) { - this.setState({ book: incomingBook }, () => { - this.onClickJoin(); - }); - } - } - // redirect to notebook when we have it - if (this.props.notebooks) { - if (this.state.awaiting) { - const book = this.state.awaiting.split('/'); - const ship = book[0]; - const notebook = book[1]; - if ((ship in this.props.notebooks) && - (notebook in this.props.notebooks[ship])) { - this.setState({ disable: false, book: '/' }); - this.props.history.push(`/~publish/notebook/${ship}/${notebook}`); - } - } - } - } - - notebooksInclude(text, notebookObj) { - let verdict = false; - let keyPair = []; - // validate that it's a worthwhile thing to check - // certainly a unit would be nice here - if (text.indexOf('/') === -1) { - return verdict; - } else { - keyPair = text.split('/'); - }; - // check both levels of object - if (keyPair[0] in notebookObj) { - if (keyPair[1] in notebookObj[keyPair[0]]) { - verdict = true; - } - } - return verdict; - } - - onClickJoin() { - const { props, state } = this; - - const text = state.book; - - let book = text.split('/'); - const ship = book[0]; - book.splice(0, 1); - book = '/' + book.join('/'); - - if (this.notebooksInclude(state.book, props.notebooks)) { - const href = `/~publish/notebook/${ship}${book}`; - return props.history.push(href); - } - - if (book.length < 2 || !urbitOb.isValidPatp(ship)) { - this.setState({ - error: true - }); - return; - } - - const actionData = { - subscribe: { - who: ship.replace('~',''), - book: /\/?(.*)/.exec(book)[1] - } - }; - - // TODO: askHistory setting - this.setState({ disable: true }); - this.props.api.publish.publishAction(actionData).catch((err) => { - console.log(err); - }).then(() => { - this.setState({ awaiting: text }); - }); - } - - bookChange(event) { - this.setState({ - book: event.target.value - }); - } - - render() { - const { state } = this; - - let joinClasses = 'db f9 green2 ba pa2 b--green2 bg-gray0-d pointer'; - if ((state.disable) || (!state.book) || (state.book === '/')) { - joinClasses = 'db f9 gray2 ba pa2 b--gray3 bg-gray0-d'; - } - - let errElem = (); - if (state.error) { - errElem = ( - - Notebook must have a valid name. - - ); - } - - return ( -
-
- {'⟵ All Notebooks'} -
-

Subscribe to an Existing Notebook

-
-

Enter a ~ship/notebook-name

-

Notebook names use lowercase, hyphens, and slashes.

-