mirror of
https://github.com/urbit/shrub.git
synced 2024-09-11 20:27:19 +03:00
Merge branch 'wh/revert-role-conversions' into bm/diary
This commit is contained in:
commit
2b8c6022f2
@ -1,20 +1,18 @@
|
||||
::
|
||||
:::: /hoon/md/mar
|
||||
:::: /hoon/atom/mar
|
||||
::
|
||||
/? 310
|
||||
::
|
||||
=, format
|
||||
:::: A minimal atom mark
|
||||
::
|
||||
=, mimes:html
|
||||
|_ txt=wain
|
||||
::
|
||||
++ grab :: convert from
|
||||
|%
|
||||
++ mime |=((pair mite octs) (to-wain q.q))
|
||||
++ noun wain :: clam from %noun
|
||||
--
|
||||
++ grow
|
||||
|%
|
||||
++ mime [/text/plain (as-octs (of-wain txt))]
|
||||
--
|
||||
|_ ato=@
|
||||
++ grab |%
|
||||
++ noun @
|
||||
++ mime |=([* p=octs] q.p)
|
||||
--
|
||||
++ grow |%
|
||||
++ mime [/application/x-urb-unknown (as-octs ato)]
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
||||
|
@ -1 +0,0 @@
|
||||
../../base-dev/mar/txt.hoon
|
18
pkg/arvo/mar/txt.hoon
Normal file
18
pkg/arvo/mar/txt.hoon
Normal file
@ -0,0 +1,18 @@
|
||||
::
|
||||
:::: /hoon/atom/mar
|
||||
::
|
||||
/? 310
|
||||
::
|
||||
:::: A minimal atom mark
|
||||
::
|
||||
=, mimes:html
|
||||
|_ ato=@
|
||||
++ grab |%
|
||||
++ noun @
|
||||
++ mime |=([* p=octs] q.p)
|
||||
--
|
||||
++ grow |%
|
||||
++ mime [/application/x-urb-unknown (as-octs ato)]
|
||||
--
|
||||
++ grad %mime
|
||||
--
|
@ -86,6 +86,9 @@
|
||||
:: entry box
|
||||
++ link-entry
|
||||
|= [pax=pith =idea:neo]
|
||||
:: make sure the pail does in fact contain %txt
|
||||
?. =(%txt p.pail.idea)
|
||||
;div: error
|
||||
:: extract information from the given pith and pail:neo
|
||||
=/ tape (trip !<(@t q.pail.idea))
|
||||
=/ subject-end (fall (find [10]~ tape) 56)
|
||||
|
21
pkg/arvo/neo/cod/std/src/con/node-counter-diff.hoon
Normal file
21
pkg/arvo/neo/cod/std/src/con/node-counter-diff.hoon
Normal file
@ -0,0 +1,21 @@
|
||||
/@ node :: manx
|
||||
/@ counter-diff :: [%inc ~]
|
||||
:: import /lib/manx-utils, which helps us work with XML
|
||||
/- manx-utils
|
||||
:: declare this is a conversion from node to counter-diff
|
||||
:- [%node %$ %counter-diff]
|
||||
|= =node
|
||||
^- counter-diff
|
||||
:: initiate the manx-utils door with node
|
||||
=/ mu ~(. manx-utils node)
|
||||
::
|
||||
:: got:mu gets an attribute from the manx by its name
|
||||
:: in this case, the =head specified in /con/number-htmx
|
||||
:: we expect the head from the manx to be %inc,
|
||||
:: but we could add more terms to that type union...
|
||||
=/ head (?(%inc) (got:mu %head))
|
||||
::
|
||||
:: return the [%inc ~] poke
|
||||
:: if we wanted to handle multiple pokes,
|
||||
:: we'd switch on the type of head here
|
||||
[head ~]
|
62
pkg/arvo/neo/cod/std/src/con/number-htmx.hoon
Normal file
62
pkg/arvo/neo/cod/std/src/con/number-htmx.hoon
Normal file
@ -0,0 +1,62 @@
|
||||
/@ number :: @ud
|
||||
:: import /lib/feather-icons
|
||||
/- feather-icons
|
||||
:: declare that this is a conversion from number to HTMX
|
||||
:- [%number %$ %htmx]
|
||||
::
|
||||
:: this gate accepts a number and a bowl:neo;
|
||||
:: we'll access bowl:neo in the UI to access the
|
||||
:: here.bowl of the shrub that's using this /con file
|
||||
|= =number
|
||||
|= =bowl:neo
|
||||
::
|
||||
:: this gate returns a manx, which is what Hoon uses
|
||||
:: to store dynamic XML nodes; in this case we'll use
|
||||
:: Sail to specify a manx that expects the HTMX library
|
||||
:: to be available on the frontend
|
||||
^- manx
|
||||
::
|
||||
:: open a <div class="p3 fc g2 ac br2">
|
||||
:: these utility classes are specified in feather.css,
|
||||
:: which this /con file expects on the frontend
|
||||
;div.p3.fc.g2.ac.br2
|
||||
:: <h1>Counter</h1>
|
||||
;h1: Counter
|
||||
:: <p>{number}</p>
|
||||
;p: {<number>}
|
||||
:: open a <form> with HTMX attributes
|
||||
;form
|
||||
::
|
||||
:: hx-post will issue a POST request to the provided
|
||||
:: url and swap response into the DOM
|
||||
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=counter-diff"
|
||||
::
|
||||
:: hx-target specifies the target for hx-post's DOM
|
||||
:: swap: the element with class "loading"
|
||||
=hx-target "find .loading"
|
||||
::
|
||||
:: hx-swap specifies how the response to hx-post's
|
||||
:: request will be swapped in relative to the target
|
||||
=hx-swap "outerHTML"
|
||||
::
|
||||
:: here, the head attribute specifies the poke that
|
||||
:: hx-post will send to the target shrub; look at
|
||||
:: /con/node-counter-diff.hoon for more on =head
|
||||
=head "inc"
|
||||
::
|
||||
:: below, the classes "loaded", "loader", and
|
||||
:: "loading" provide loading spinner behavior on
|
||||
:: sending and receiving this form's POST request
|
||||
::
|
||||
:: <button class="bd1 br1 pr b1 hover loader">
|
||||
;button.bd1.br1.p2.b1.hover.loader
|
||||
:: <span class="loaded">Increment</span>
|
||||
;span.loaded: Increment
|
||||
:: <span class="loading">
|
||||
;span.loading
|
||||
:: import +loading sail from /lib/feather-icons
|
||||
;+ loading.feather-icons
|
||||
== :: </span>
|
||||
== :: </button>
|
||||
== :: </form>
|
||||
== :: </div>
|
318
pkg/arvo/neo/cod/std/src/fil/counter.md
Normal file
318
pkg/arvo/neo/cod/std/src/fil/counter.md
Normal file
@ -0,0 +1,318 @@
|
||||
# Tutorial 1: Counter
|
||||
|
||||
One of the simplest shrubs imaginable is a counter that stores one number and takes one poke: increment the number.
|
||||
|
||||
By the end of this tutorial you'll understand the structure of a shrub, and how to write a trivial one of your own. This won't explain shrubbery from first principles — you don’t need to understand it from first principles — but you'll see how similar a shrub is to a Gall agent and where they differ.
|
||||
|
||||
You’ll also get a glimpse of how one shrub can accomodate various frontend interfaces. We’ll make a simple frontend for Sky, a prototype namespace browser.
|
||||
|
||||
## Counter in Gall and Shrubbery
|
||||
Here's the Gall agent we'll reimplement in shrubbery. It stores one number and takes one poke, `%inc`, to increment the number.
|
||||
|
||||
```hoon
|
||||
/+ dbug, default-agent, verb
|
||||
|%
|
||||
+$ versioned-state
|
||||
$% state-0
|
||||
==
|
||||
+$ state-0
|
||||
$: %0
|
||||
value=@ud
|
||||
==
|
||||
+$ counter-action
|
||||
$% [%inc ~]
|
||||
==
|
||||
+$ card card:agent:gall
|
||||
--
|
||||
::
|
||||
%+ verb &
|
||||
%- agent:dbug
|
||||
=| state-0
|
||||
=* state -
|
||||
^- agent:gall
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
::
|
||||
++ on-init on-init:def
|
||||
++ on-peek on-peek:def
|
||||
++ on-watch on-watch:def
|
||||
++ on-arvo on-arvo:def
|
||||
++ on-leave on-leave:def
|
||||
++ on-agent on-agent:def
|
||||
++ on-fail on-fail:def
|
||||
++ on-save
|
||||
!>(state)
|
||||
::
|
||||
++ on-load
|
||||
|= old=vase
|
||||
^- (quip card _this)
|
||||
:- ~
|
||||
%= this
|
||||
state !<(state-0 old)
|
||||
==
|
||||
::
|
||||
++ on-poke
|
||||
|= [=mark =vase]
|
||||
^- (quip card _this)
|
||||
?+ mark
|
||||
(on-poke:def mark vase)
|
||||
::
|
||||
%noun
|
||||
=/ act
|
||||
!<(counter-action vase)
|
||||
?+ -.act
|
||||
(on-poke:def mark vase)
|
||||
::
|
||||
%inc
|
||||
:- ~
|
||||
%= this
|
||||
value +(value)
|
||||
==
|
||||
==
|
||||
==
|
||||
--
|
||||
```
|
||||
|
||||
Here's the same thing in shrubbery.
|
||||
|
||||
```hoon
|
||||
/@ number
|
||||
/@ counter-diff
|
||||
^- kook:neo
|
||||
|%
|
||||
++ state pro/%number
|
||||
++ poke (sy %counter-diff ~)
|
||||
++ kids *kids:neo
|
||||
++ deps *deps:neo
|
||||
++ form
|
||||
^- form:neo
|
||||
|_ [=bowl:neo =aeon:neo stud:neo state-vase=vase]
|
||||
+* state !<(number state-vase)
|
||||
++ init
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
`(need old)
|
||||
++ poke
|
||||
|= [=stud:neo vaz=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?> =(%counter-diff stud)
|
||||
=/ act !<(counter-diff vaz)
|
||||
?> =(-.act %inc) :: XX can we remove this line?
|
||||
`number/!>(+(state))
|
||||
--
|
||||
--
|
||||
```
|
||||
|
||||
Let’s set up a fakeship that has `/base/app/neo.hoon`, the prototype “shrub runner”, then go over the code piece by piece.
|
||||
|
||||
## Counter shrub, explained
|
||||
Now let’s take a closer look at the counter shrub. You’ll find a version of `counter.hoon` with comments in your `/imp` folder.
|
||||
|
||||
```hoon
|
||||
:: /imp/counter.hoon
|
||||
/@ number
|
||||
/@ counter-diff
|
||||
```
|
||||
|
||||
These lines import two files from our `/pro` folder: `number.hoon` and `counter-diff.hoon`.
|
||||
|
||||
```hoon
|
||||
:: /pro/number.hoon
|
||||
,@ud
|
||||
```
|
||||
|
||||
```hoon
|
||||
:: /pro/counter-diff.hoon
|
||||
,[%inc ~]
|
||||
```
|
||||
|
||||
The folder structure you have to work with right now is messier than it will be in the final product. This is an artefact of prototyping shrubbery in a Gall agent in the `%base` desk.
|
||||
|
||||
The only folders you need to understand for this tutorial are `/pro`, `/imp`, and `/con`.
|
||||
- `/pro` for protocols. Like `/sur`, this is where your custom types live.
|
||||
- `/imp` for implementations. Like `/app`, this is where your Gall agent-like shrubs live.
|
||||
- `/con` for conversions. Like `/mar`, this is where you define rules for transforming nouns in your desk.
|
||||
|
||||
Let’s look at the rest of the `/imp` file.
|
||||
|
||||
```hoon
|
||||
/@ number
|
||||
/@ counter-diff
|
||||
::
|
||||
:: outer core of a shrub
|
||||
^- kook:neo
|
||||
|%
|
||||
::
|
||||
:: the state of counter is a %number, just a @ud
|
||||
++ state
|
||||
^- curb:neo
|
||||
[%pro %number]
|
||||
::
|
||||
:: the set of pokes that counter
|
||||
:: takes only contains %counter-diff
|
||||
++ poke
|
||||
^- (set stud:neo)
|
||||
(sy %counter-diff ~)
|
||||
::
|
||||
::
|
||||
:: counter does not "constrain" its children;
|
||||
:: any shrub can be made below this shrub in the
|
||||
:: namespace, they can have any state and any kids
|
||||
++ kids
|
||||
^- kids:neo
|
||||
*kids:neo
|
||||
::
|
||||
:: counter has no other shrubs as dependencies
|
||||
++ deps
|
||||
^- deps:neo
|
||||
*deps:neo
|
||||
::
|
||||
:: inner core of a shrub
|
||||
++ form
|
||||
^- form:neo
|
||||
:: treat this door's sample as boilerplate
|
||||
|_ [=bowl:neo =aeon:neo stud:neo state-vase=vase]
|
||||
::
|
||||
:: de-vase the state; we don't know what it is,
|
||||
:: in most cases it will be counter's old state
|
||||
+* state !<(number state-vase)
|
||||
::
|
||||
:: +init, like +on-init
|
||||
++ init
|
||||
::
|
||||
:: minimal +init, just returns the
|
||||
:: initial state passed in on %make
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
[~ (need old)]
|
||||
::
|
||||
:: +poke, like +on-poke
|
||||
++ poke
|
||||
::
|
||||
:: a stud (e.g. %number or %counter-diff) is kind
|
||||
:: of like a mark, it only gets more complicated
|
||||
:: than that with types from other desks/ships
|
||||
|= [=stud:neo vaz=vase]
|
||||
::
|
||||
:: return a (list card:neo) and a
|
||||
:: pail, which is a (pair stud vase)
|
||||
^- (quip card:neo pail:neo)
|
||||
::
|
||||
:: assert that the poke's stud is %counter-diff,
|
||||
:: which protects counter from evil vases
|
||||
?> =(%counter-diff stud)
|
||||
=/ act
|
||||
!<(counter-diff vaz)
|
||||
?> =(-.act %inc)
|
||||
::
|
||||
:: return no cards and a pail
|
||||
[~ [%number !>(+(state))]]
|
||||
--
|
||||
--
|
||||
```
|
||||
|
||||
Once you’ve saved `/imp/counter.hoon`, run `|commit %base` and Neo will add it to its state. We can now interact with this shrub in the Dojo.
|
||||
|
||||
## Poking the shrub
|
||||
A `card:neo` is a `(pair pith note)`.
|
||||
|
||||
A `pith` is a list of head-tagged cells forming a typed path. This is the location of the shrub to which your card will be sent.
|
||||
* The path `/examples/counter/one` will be a pith `~[%examples %counter %one]`.
|
||||
* The path `/~sampel/examples/counter/one` will be a pith `~[[%p ~sampel] %examples %counter %one]`.
|
||||
* The path `/~sampel/examples/counter/1` will be a pith `~[[%p ~sampel] %examples %counter [%ud 1]]`.
|
||||
|
||||
A `note` is one of the four types of command any shrub will accept.
|
||||
|
||||
```hoon
|
||||
+$ note
|
||||
$% [%make made] :: create a shrub
|
||||
[%poke =pail] :: poke a shrub
|
||||
[%tomb cas=(unit case)] :: tombstone a shrub
|
||||
[%cull ~] :: ???
|
||||
==
|
||||
```
|
||||
|
||||
If the `pith` doesn’t correspond to the location of an existing shrub, you’ll have to make a shrub there before doing anything else.
|
||||
|
||||
Let’s `%make` a shrub at path `/examples/counters/one` from the Dojo, giving it an initial state of `0`. We’ll explain the structure of the `%make` note in more detail in the Diary tutorial.
|
||||
|
||||
```
|
||||
:neo &neo-card [~[[%p our] %examples %counters %one] [%make %counter `[%number !>(0)] ~]]
|
||||
```
|
||||
|
||||
You should see `>> %make /examples/counters/one` in the Dojo if successful.
|
||||
|
||||
Now we can now send a `%poke` to the counter shrub at this path.
|
||||
|
||||
```
|
||||
:neo &neo-card [~[[%p our] %examples %counters %one] [%poke [%counter-diff !>([%inc ~])]]]
|
||||
```
|
||||
|
||||
At time of writing there is no easy way to inspect the state of a shrub from the Dojo. We’ll just have to build a frontend and hope it all just works.
|
||||
|
||||
## Counter frontend in Sky
|
||||
Shrubbery aims to be interface-agnostic. One part of that vision is `/con` files, which make it possible to convert data from one backend type to any frontend type, and one frontend type to any backend type. Here are Counter’s `/con` files.
|
||||
|
||||
### Converting number to HTMX
|
||||
```hoon
|
||||
:: /con/number-htmx.hoon
|
||||
/@ number :: @ud
|
||||
/- feather-icons
|
||||
:- [%number %$ %htmx]
|
||||
|= =number
|
||||
|= =bowl:neo
|
||||
^- manx
|
||||
;div.p3.fc.g2.ac.br2
|
||||
;h1: Counter
|
||||
;p: {<number>}
|
||||
;form
|
||||
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=counter-diff"
|
||||
=hx-target "find .loading"
|
||||
=hx-swap "outerHTML"
|
||||
=head "inc"
|
||||
;button.bd1.br1.p2.b1.hover.loader
|
||||
;span.loaded: Increment
|
||||
;span.loading
|
||||
;+ loading.feather-icons
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
||||
```
|
||||
|
||||
This “converts” the `number` type to a `manx`, specifically targeting a frontend that uses the [HTMX](https://htmx.org/) library. You don’t need to know HTMX to build shrubbery frontends or to follow the rest of this tutorial. If you want to understand the HTMX above in more detail, see `/con/number-htmx.hoon` for line-by-line comments.
|
||||
|
||||
This isn’t a 1:1 conversion from one data type to another; we’re not converting Hoon `number=1` to JSON `{ "number": 1 }`. If a frontend asks for a `number` in the form of HTMX, we return some [Sail](https://docs.urbit.org/language/hoon/guides/sail) that interpolates the `number` in a basic interface consisting of a heading, the number, and one button to send an `%inc` poke to the Counter shrub.
|
||||
|
||||
### Converting Node to %counter-diff
|
||||
```hoon
|
||||
:: /con/node-counter-diff.hoon
|
||||
/@ node :: manx
|
||||
/@ counter-diff :: [%inc ~]
|
||||
/- manx-utils
|
||||
:- [%node %$ %counter-diff]
|
||||
|= =node
|
||||
^- counter-diff
|
||||
=/ mu ~(. manx-utils node)
|
||||
=/ head (?(%inc) (got:mu %head))
|
||||
[head ~]
|
||||
```
|
||||
|
||||
This is a more straightforward conversion from a dynamic XML node (in this case, HTMX), to a `%counter-diff`. Using the [manx-utils](https://github.com/tinnus-napbus/manx-utils) Hoon library for brevity, we extract the XML node’s `head` attribute (which has been converted to the term `%inc` on its way here) and use that to form the `%counter-diff`, which is `[%inc ~]`. See `/con/node-counter-diff.hoon` for line-by-line comments.
|
||||
|
||||
## Testing the Counter in Sky
|
||||
The Sky homepage shows you one tile for all of the shrubs who are the immediate children of your `/home` shurb, which was made for you upon booting `%neo` for the first time. You won’t see a Counter tile there because there is no `/counter` shrub beneath `/home`, so let’s make one.
|
||||
|
||||
```
|
||||
:neo &neo-card [~[[%p our] %home %counter] [%make %counter `[%number !>(0)] ~]]
|
||||
```
|
||||
|
||||
If you refresh your browser you should now see a tile labelled “counter”. Click there to see the Counter frontend from the `/con` file and increment the state of the `/counter` shrub.
|
||||
|
||||
## Building on the Counter
|
||||
If you know your way around Gall, you should now be able to make some minor changes to the counter example above. Try the following:
|
||||
|
||||
* Initialize the shrub with a default state if the given `(unit vase)` in `+init` is empty.
|
||||
* Add more pokes like `%dec`, `%add`, and `%sub` on the backend.
|
||||
* Add those pokes to the frontend interface, with one button per poke.
|
80
pkg/arvo/neo/cod/std/src/imp/counter.hoon
Normal file
80
pkg/arvo/neo/cod/std/src/imp/counter.hoon
Normal file
@ -0,0 +1,80 @@
|
||||
/@ number :: @ud
|
||||
/@ counter-diff :: [%inc ~]
|
||||
::
|
||||
:: outer core of a shrub: define state, pokes,
|
||||
:: dependencies, and kids
|
||||
^- kook:neo
|
||||
|%
|
||||
::
|
||||
:: the state of the counter is a %number, just a @ud
|
||||
:: a curb:neo is a constraint imposed on a shrub
|
||||
++ state
|
||||
^- curb:neo
|
||||
[%pro %number]
|
||||
::
|
||||
:: the set of pokes that counter
|
||||
:: takes only contains %counter-diff
|
||||
++ poke
|
||||
^- (set stud:neo)
|
||||
(sy %counter-diff ~)
|
||||
::
|
||||
::
|
||||
:: counter does not constrain the type and behaviour of
|
||||
:: its children; any shrub can be made below this shrub
|
||||
:: in the tree, they can have any state, kids, or pokes
|
||||
++ kids
|
||||
^- kids:neo
|
||||
*kids:neo
|
||||
::
|
||||
:: counter has no other shrubs as dependencies
|
||||
++ deps
|
||||
^- deps:neo
|
||||
*deps:neo
|
||||
::
|
||||
:: inner core of a shrub: business logic
|
||||
++ form
|
||||
^- form:neo
|
||||
:: treat this door's sample as boilerplate
|
||||
|_ [=bowl:neo =aeon:neo =pail:neo]
|
||||
::
|
||||
:: +init, like +on-init
|
||||
++ init
|
||||
::
|
||||
:: minimal +init, just returns the
|
||||
:: initial state passed in on %make
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
[~ (need old)]
|
||||
::
|
||||
:: +poke, like +on-poke
|
||||
++ poke
|
||||
::
|
||||
:: a stud (e.g. %number or %counter-diff) is
|
||||
:: like a mark
|
||||
|= [=stud:neo vaz=vase]
|
||||
::
|
||||
:: return a (list card:neo) and a
|
||||
:: pail, which is a (pair stud vase)
|
||||
^- (quip card:neo pail:neo)
|
||||
::
|
||||
:: assert the stud of the pail (pair stud vase),
|
||||
:: which is the shrub's state given in the sample
|
||||
:: (technically unnecessary in this case, but good
|
||||
:: hygiene)
|
||||
?> =(p.pail %number)
|
||||
::
|
||||
:: de-vase the payload's vase through the number
|
||||
:: type; note the difference between the number
|
||||
:: type and the %number stud
|
||||
=/ state !<(number q.pail)
|
||||
::
|
||||
:: assert that the poke's stud is %counter-diff
|
||||
?> =(%counter-diff stud)
|
||||
=/ act
|
||||
!<(counter-diff vaz)
|
||||
?> =(-.act %inc)
|
||||
::
|
||||
:: return no cards and a pail
|
||||
[~ [%number !>(+(state))]]
|
||||
--
|
||||
--
|
@ -1,67 +1,74 @@
|
||||
/@ dm-diff
|
||||
/@ message
|
||||
=>
|
||||
|%
|
||||
++ card card:neo
|
||||
--
|
||||
^- kook:neo
|
||||
|%
|
||||
++ state pro/%sig
|
||||
++ poke (sy %dm-diff %rely ~)
|
||||
++ state pro/%ship :: who I'm chatting with
|
||||
++ poke (sy %dm-diff ~)
|
||||
++ kids
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%da |]
|
||||
[pro/%message ~]
|
||||
==
|
||||
++ deps
|
||||
%- ~(gas by *deps:neo)
|
||||
:~
|
||||
::
|
||||
:- %link
|
||||
::
|
||||
:+ req=| [pro/%sig (sy %dm-diff ~)]
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%da |]
|
||||
[pro/%message ~]
|
||||
==
|
||||
:~ :- [|/%theirs |]
|
||||
[pro/%message-pub (sy %sig ~)]
|
||||
:- [|/%mine |]
|
||||
[pro/%message-sub (sy %sig ~)]
|
||||
==
|
||||
++ deps *deps:neo
|
||||
++ form
|
||||
^- form:neo
|
||||
|_ [=bowl:neo =aeon:neo sta=pail:neo]
|
||||
++ poke
|
||||
|= [=stud:neo vax=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?: =(%rely stud)
|
||||
=+ !<([=term =stem:neo] vax)
|
||||
?> ?=(%y -.q.stem)
|
||||
=/ =pail:neo pail:(snag 0 ~(val by kids.q.stem))
|
||||
=+ !<(=message q.pail)
|
||||
:: TODO handle
|
||||
?< =(our.bowl from.message)
|
||||
:_ sta
|
||||
:_ ~
|
||||
:*
|
||||
(welp here.bowl ~[da/now.bowl])
|
||||
%make
|
||||
[%message `pail ~]
|
||||
==
|
||||
?> =(%dm-diff stud)
|
||||
=/ poke !<(dm-diff vax)
|
||||
?> =(our ship.src):bowl
|
||||
?> =(%msg -.poke)
|
||||
:_ sta
|
||||
:~
|
||||
:*
|
||||
(welp were.bowl ~[da/now.bowl])
|
||||
%make
|
||||
[%message `message/!>(message.poke) ~]
|
||||
==
|
||||
==
|
||||
|_ [=bowl:neo =aeon:neo state=pail:neo]
|
||||
++ init
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
`sig/!>(~)
|
||||
?~ old !!
|
||||
?> =(%dm-diff p.u.old)
|
||||
=/ poke !<(dm-diff q.u.old)
|
||||
?+ -.poke !!
|
||||
:: create me with a pith to a service provider
|
||||
:: to start a new DM with them
|
||||
%initiate
|
||||
:_ ship/!>(partner.poke)
|
||||
:~ :- (snoc here.bowl %pub)
|
||||
[%make %message-pub ~ ~]
|
||||
::
|
||||
:- provider.poke
|
||||
[%poke dm-diff/!>([%invited here.bowl])]
|
||||
==
|
||||
::
|
||||
:: create me with a pith to an inviter's dm
|
||||
:: to accept their DM request
|
||||
%invited
|
||||
:_ ship/!>(partner.poke)
|
||||
:~ :- (snoc here.bowl %pub)
|
||||
[%make %message-pub ~ ~]
|
||||
::
|
||||
:- (snoc here.bowl %sub)
|
||||
[%make %message-sub ~ (malt ~[[%pub (snoc dm.poke %pub)]])]
|
||||
::
|
||||
:- dm.poke
|
||||
[%poke dm-diff/!>([%acked here.bowl])]
|
||||
==
|
||||
==
|
||||
++ poke
|
||||
|= [=stud:neo vax=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?> =(%dm-diff stud)
|
||||
=/ poke !<(dm-diff vax)
|
||||
?+ -.poke !!
|
||||
:: invitee pokes me with a pith to their DM
|
||||
:: to finalize the negotiation
|
||||
%acked
|
||||
=/ partner !<(ship q.state)
|
||||
?> =(partner ship.src.bowl)
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl %sub)
|
||||
[%make %message-sub ~ (malt ~[[%pub (snoc dm.poke %pub)]])]
|
||||
==
|
||||
::
|
||||
%post
|
||||
?> =(our ship.src):bowl
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl %pub)
|
||||
[%poke txt/!>(text.poke)]
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
||||
--
|
103
pkg/arvo/neo/cod/std/src/imp/groupchat.hoon
Normal file
103
pkg/arvo/neo/cod/std/src/imp/groupchat.hoon
Normal file
@ -0,0 +1,103 @@
|
||||
/@ groupchat
|
||||
/@ groupchat-diff
|
||||
^- kook:neo
|
||||
|%
|
||||
++ state pro/%groupchat
|
||||
++ poke (sy %groupchat-diff ~)
|
||||
++ kids
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%pub |]
|
||||
[pro/%message-pub (sy %sig ~)]
|
||||
:- [|/%sub |]
|
||||
[pro/%message-sub (sy %sig ~)]
|
||||
==
|
||||
++ deps *deps:neo
|
||||
++ form
|
||||
^- form:neo
|
||||
|_ [=bowl:neo =aeon:neo state=pail:neo]
|
||||
++ init
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
:: default case: make new groupchat with self as only member,
|
||||
:: and subscribe to that publisher
|
||||
:: XX - maybe move ordering is unpredictable here
|
||||
?~ old
|
||||
:_ :- %groupchat
|
||||
!>([(sy our.bowl ~) ~ (snoc here.bowl %pub)])
|
||||
:~ :- (snoc here.bowl %pub)
|
||||
[%make %message-pub ~ ~]
|
||||
::
|
||||
:- (snoc here.bowl %sub)
|
||||
[%make %message-sub ~ (malt ~[[%pub (snoc here.bowl %pub)]])]
|
||||
==
|
||||
:: otherwise, I've been created as an invitee to
|
||||
:: someone else's groupchat
|
||||
?> =(%groupchat-diff p.u.old)
|
||||
=/ poke !<(groupchat-diff q.u.old)
|
||||
?+ -.poke !!
|
||||
%invited
|
||||
:_ groupchat/!>([~ ~ host.poke])
|
||||
:~ :- (snoc here.bowl %sub)
|
||||
[%make %message-sub ~ (malt ~[[%pub (snoc host.poke %pub)]])]
|
||||
::
|
||||
:- host.poke
|
||||
[%poke groupchat-diff/!>([%acked ~])]
|
||||
==
|
||||
==
|
||||
++ poke
|
||||
|= [=stud:neo vax=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?> =(%groupchat-diff stud)
|
||||
=/ sta !<(groupchat q.state)
|
||||
=/ poke !<(groupchat-diff vax)
|
||||
?+ -.poke !!
|
||||
:: if I'm the host, poke someone's provider to invite them to chat
|
||||
%invite
|
||||
?> =(our ship.src):bowl
|
||||
?< (~(has in members.sta) ship.poke)
|
||||
:: ?> =(our.bowl ->.host.sta) :: XX need @p, have @t ?
|
||||
:_ :- %groupchat
|
||||
!>(sta(pending (~(put in pending.sta) ship.poke)))
|
||||
:~ :- provider.poke
|
||||
[%poke groupchat-diff/!>([%invited here.bowl])]
|
||||
==
|
||||
::
|
||||
:: remove someone from chat. this only removes their ability to post;
|
||||
:: they'll still be receiving new messages!
|
||||
%remove
|
||||
?> =(our ship.src):bowl
|
||||
?> (~(has in members.sta) ship.poke)
|
||||
:- ~
|
||||
:- %groupchat
|
||||
!> %= sta
|
||||
pending (~(del in pending.sta) ship.src.bowl)
|
||||
members (~(del in members.sta) ship.src.bowl)
|
||||
==
|
||||
::
|
||||
:: when invitee acks, remove them from pending
|
||||
:: and add them to pub's permissions
|
||||
%acked
|
||||
?> (~(has in pending.sta) ship.src.bowl)
|
||||
:- ~
|
||||
:- %groupchat
|
||||
!> %= sta
|
||||
pending (~(del in pending.sta) ship.src.bowl)
|
||||
members (~(put in members.sta) ship.src.bowl)
|
||||
==
|
||||
::
|
||||
%post-to-host
|
||||
:_ state
|
||||
:~ :- host.sta
|
||||
[%poke groupchat-diff/!>([%host-to-pub text.poke])]
|
||||
==
|
||||
::
|
||||
%host-to-pub
|
||||
?> (~(has in members.sta) ship.src.bowl)
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl %pub)
|
||||
[%poke message/!>([ship.src.bowl now.bowl text.poke])]
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
@ -198,12 +198,14 @@
|
||||
^- fief:neo
|
||||
:- req=|
|
||||
^- quay:neo
|
||||
:- [[%or rol/[%ui-main pro/%htmx] pro/%htmx ~] ~]
|
||||
:- [pro/%htmx ~]
|
||||
:::- [[%or rol/[%ui-main pro/%htmx] pro/%htmx ~] ~]
|
||||
^- (unit port:neo)
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- &
|
||||
`lash:neo`[[%or pro/%htmx any/~ ~] ~]
|
||||
`lash:neo`[any/~ ~]
|
||||
::`lash:neo`[[%or rol/[%link pro/%htmx] pro/%htmx any/~ ~] ~]
|
||||
==
|
||||
==
|
||||
::
|
||||
|
41
pkg/arvo/neo/cod/std/src/imp/message-pub.hoon
Normal file
41
pkg/arvo/neo/cod/std/src/imp/message-pub.hoon
Normal file
@ -0,0 +1,41 @@
|
||||
/@ txt
|
||||
/@ message
|
||||
::
|
||||
^- kook:neo
|
||||
|%
|
||||
++ state pro/%sig
|
||||
++ poke (sy %message %txt ~)
|
||||
++ kids
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%da |]
|
||||
[pro/%message (sy %sig ~)]
|
||||
==
|
||||
++ deps *deps:neo
|
||||
++ form
|
||||
^- form:neo
|
||||
|_ [=bowl:neo =aeon:neo state=pail:neo]
|
||||
++ init
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
[~ sig/!>(~)]
|
||||
::
|
||||
++ poke
|
||||
|= [=stud:neo vax=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?> =(our ship.src):bowl
|
||||
:_ state
|
||||
?+ stud !!
|
||||
%message
|
||||
=/ msg !<(message vax)
|
||||
:~ :- (welp here.bowl ~[da/now.msg])
|
||||
[%make %message `message/vax ~]
|
||||
==
|
||||
%txt
|
||||
=/ contents=@t !<(txt vax)
|
||||
:~ :- (welp here.bowl ~[da/now.bowl])
|
||||
[%make %message `message/!>([ship.src.bowl now.bowl contents]) ~]
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
51
pkg/arvo/neo/cod/std/src/imp/message-sub.hoon
Normal file
51
pkg/arvo/neo/cod/std/src/imp/message-sub.hoon
Normal file
@ -0,0 +1,51 @@
|
||||
/@ message
|
||||
^- kook:neo
|
||||
|%
|
||||
++ state pro/%sig
|
||||
++ poke ~
|
||||
++ kids
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%da |]
|
||||
[pro/%message ~]
|
||||
==
|
||||
++ deps
|
||||
%- ~(gas by *deps:neo)
|
||||
:~ :- %pub
|
||||
:+ req=& [pro/%sig (sy %sig ~)]
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%da |]
|
||||
[pro/%message ~]
|
||||
==
|
||||
==
|
||||
++ form
|
||||
^- form:neo
|
||||
|_ [=bowl:neo =aeon:neo state=pail:neo]
|
||||
++ init
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
[~ sig/!>(~)]
|
||||
::
|
||||
++ poke
|
||||
|= [=stud:neo vax=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?> =(%rely stud)
|
||||
:_ state
|
||||
=+ !<([=term =stem:neo] vax)
|
||||
?> ?=(%y -.q.stem)
|
||||
:: only get new kids
|
||||
=/ kids
|
||||
%+ skim
|
||||
~(val by kids.q.stem)
|
||||
|= [=ever:neo =mode:neo =pail:neo]
|
||||
=(%add mode)
|
||||
?: =(~ kids)
|
||||
~
|
||||
=/ pai=pail:neo pail:(snag 0 kids)
|
||||
=/ mes !<(message q.pai)
|
||||
:~ :- (welp here.bowl ~[da/now.mes])
|
||||
[%make [%message `pai ~]]
|
||||
==
|
||||
--
|
||||
--
|
73
pkg/arvo/neo/cod/std/src/imp/messenger.hoon
Normal file
73
pkg/arvo/neo/cod/std/src/imp/messenger.hoon
Normal file
@ -0,0 +1,73 @@
|
||||
/@ dm-diff
|
||||
/@ groupchat-diff
|
||||
/@ messenger-diff
|
||||
^- kook:neo
|
||||
|%
|
||||
++ state pro/%sig
|
||||
++ poke (sy %dm-diff %groupchat-diff ~)
|
||||
++ kids
|
||||
:+ ~ %y
|
||||
%- ~(gas by *lads:neo)
|
||||
:~ :- [|/%t |]
|
||||
[pro/%dm (sy %dm-diff ~)]
|
||||
:- [|/%t |]
|
||||
[pro/%groupchat (sy %groupchat-diff ~)]
|
||||
==
|
||||
++ deps *deps:neo
|
||||
++ form
|
||||
^- form:neo
|
||||
|_ [=bowl:neo =aeon:neo state=pail:neo]
|
||||
++ init
|
||||
|= old=(unit pail:neo)
|
||||
^- (quip card:neo pail:neo)
|
||||
[~ sig/!>(~)]
|
||||
::
|
||||
++ poke
|
||||
|= [=stud:neo vax=vase]
|
||||
^- (quip card:neo pail:neo)
|
||||
?+ stud !!
|
||||
%dm-diff
|
||||
=/ poke !<(dm-diff vax)
|
||||
?> =(%invited -.poke)
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl p/ship.src.bowl)
|
||||
[%make %dm `dm-diff/vax ~]
|
||||
==
|
||||
::
|
||||
%groupchat-diff
|
||||
=/ poke !<(groupchat-diff vax)
|
||||
?+ -.poke !!
|
||||
%invited
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl (rear host.poke))
|
||||
[%make %groupchat `groupchat-diff/vax ~]
|
||||
==
|
||||
==
|
||||
::
|
||||
%messenger-diff
|
||||
?> =(our ship.src):bowl
|
||||
=/ poke !<(messenger-diff vax)
|
||||
?- -.poke
|
||||
%new-dm
|
||||
=/ provider ~[p/partner.poke %home %messenger]
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl p/partner.poke)
|
||||
[%make %dm `dm-diff/!>([%initiate partner.poke provider]) ~]
|
||||
==
|
||||
::
|
||||
%new-groupchat
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl t/name.poke)
|
||||
[%make %groupchat ~ ~]
|
||||
==
|
||||
::
|
||||
%invite-to-groupchat
|
||||
=/ provider ~[p/ship.poke %home %messenger]
|
||||
:_ state
|
||||
:~ :- (snoc here.bowl t/name.poke)
|
||||
[%poke groupchat-diff/!>([%invite ship.poke provider])]
|
||||
==
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
1
pkg/arvo/neo/cod/std/src/pro/counter-diff.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/counter-diff.hoon
Normal file
@ -0,0 +1 @@
|
||||
,[%inc ~]
|
@ -1,2 +1,7 @@
|
||||
/@ message
|
||||
,[%msg =message]
|
||||
$% [%initiate partner=ship provider=pith]
|
||||
[%invited partner=ship dm=pith]
|
||||
::
|
||||
[%acked dm=pith]
|
||||
::
|
||||
[%post text=@t]
|
||||
==
|
||||
|
7
pkg/arvo/neo/cod/std/src/pro/groupchat-diff.hoon
Normal file
7
pkg/arvo/neo/cod/std/src/pro/groupchat-diff.hoon
Normal file
@ -0,0 +1,7 @@
|
||||
$% [%invite =ship provider=pith]
|
||||
[%remove =ship]
|
||||
[%invited host=pith]
|
||||
[%acked ~]
|
||||
[%post-to-host text=@t]
|
||||
[%host-to-pub text=@t]
|
||||
==
|
4
pkg/arvo/neo/cod/std/src/pro/groupchat.hoon
Normal file
4
pkg/arvo/neo/cod/std/src/pro/groupchat.hoon
Normal file
@ -0,0 +1,4 @@
|
||||
$: members=(set ship)
|
||||
pending=(set ship)
|
||||
host=pith
|
||||
==
|
4
pkg/arvo/neo/cod/std/src/pro/messenger-diff.hoon
Normal file
4
pkg/arvo/neo/cod/std/src/pro/messenger-diff.hoon
Normal file
@ -0,0 +1,4 @@
|
||||
$% [%new-dm partner=ship]
|
||||
[%new-groupchat name=@t]
|
||||
[%invite-to-groupchat name=@t =ship]
|
||||
==
|
1
pkg/arvo/neo/cod/std/src/pro/number.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/number.hoon
Normal file
@ -0,0 +1 @@
|
||||
,@ud
|
1
pkg/arvo/neo/cod/std/src/pro/ship.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/ship.hoon
Normal file
@ -0,0 +1 @@
|
||||
ship
|
3
pkg/arvo/neo/cod/std/src/pro/ships-diff.hoon
Normal file
3
pkg/arvo/neo/cod/std/src/pro/ships-diff.hoon
Normal file
@ -0,0 +1,3 @@
|
||||
$% [%put =ship]
|
||||
[%del =ship]
|
||||
==
|
1
pkg/arvo/neo/cod/std/src/pro/ships.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/ships.hoon
Normal file
@ -0,0 +1 @@
|
||||
(set ship)
|
Loading…
Reference in New Issue
Block a user