Merge branch 'na-release/next-vere' into jt/minkleton
* na-release/next-vere: (1169 commits) jets: fix broken jets so ~marzod can boot. jets: hook up preexisting +repn jet. jets: add empty hashes jets: review comments Revert "Revert "u3: clear cached mugs on cell edit"" jets: +welp and +zing jets: fix memory leak in +run:in jet: +find jets: +all:by and +any:by jets: +urn:by jet: +rep:by jet: +rep:in jets: +apt:in jets: +run:in jets: final cleanup jets: reenable +uni:by jets: jet +apt:by jets: +key:by and +wyt:by jets: +run:by jet: final cleanup ...
39
.github/ISSUE_TEMPLATE/kernel-or-runtime-bug-report.md
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
name: Kernel or runtime bug report
|
||||||
|
about: Use this template to file a bug for low-level system components, e.g. Hoon,
|
||||||
|
Arvo, Zuse, the vanes, Vere, etc.
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- A good bug report, description of a crash, etc., should ideally be *reproducible*, with clear steps as to how another developer can replicate and examine your problem. That said, this isn't always possible; some bugs depend on having created a complicated or unusual state, or can otherwise simply be difficult to trigger again (say, you encountered it in the last continuity era).
|
||||||
|
|
||||||
|
Your issue should thus at a minimum be *informative*. The best advice here is probably "don't write bad issues," where "bad" is a matter of judgment and taste. Issues that the maintainers don't judge to be sufficiently useful or informative may be closed. -->
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behaviour:
|
||||||
|
1. ...
|
||||||
|
2. ...
|
||||||
|
3. ...
|
||||||
|
|
||||||
|
**Expected behaviour**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**System (please supply the following information, if relevant):**
|
||||||
|
- OS: [e.g. macOS, linux64, FreeBSD]
|
||||||
|
- Vere and Urbit OS versions
|
||||||
|
- Your ship's `%base` hash (use `.^(@uv %cz /=base=)` to check)
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
|
|
||||||
|
**Notify maintainers**
|
||||||
|
If you happen to know who the appropriate maintainers are, consider mentioning them with an @ here. You may want to use `git blame` to see who has last touched any relevant code.
|
39
.github/ISSUE_TEMPLATE/os1-bug-report.md
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
name: OS1 Bug report
|
||||||
|
about: 'Use this template to file a bug for any OS1 app: Chat, Publish, Links, Groups,
|
||||||
|
Weather or Clock'
|
||||||
|
title: ''
|
||||||
|
labels: OS1
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem. If possible, please also screenshot your browser's dev console. Here are [Chrome's docs](https://developers.google.com/web/tools/chrome-devtools/open) for using this feature.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. MacOS 10.15.3]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Base hash of your urbit ship. Run ` .^(@uv %cz /=base=)` in Dojo to see this.
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Base hash of your urbit ship. Run ` .^(@uv %cz /=base=)` in Dojo to see this.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
57
.gitignore
vendored
@ -1,23 +1,46 @@
|
|||||||
/out
|
# nix symlink artifacts
|
||||||
/result
|
#
|
||||||
/result-*
|
result
|
||||||
/work
|
result-*
|
||||||
|
|
||||||
|
# common dev piers
|
||||||
|
#
|
||||||
/zod
|
/zod
|
||||||
/bus
|
/bus
|
||||||
/fakezod*
|
/nec
|
||||||
tags
|
/fakezod
|
||||||
TAGS
|
|
||||||
|
# package manager caches
|
||||||
|
#
|
||||||
|
.stack-work
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# build and release artifacts
|
||||||
|
#
|
||||||
cross/
|
cross/
|
||||||
release/
|
release/
|
||||||
.stack-work
|
dist
|
||||||
|
/out
|
||||||
|
/work
|
||||||
|
|
||||||
|
# landscape dev
|
||||||
|
#
|
||||||
|
urbitrc
|
||||||
|
*-min.js
|
||||||
|
pkg/interface/link-webext/web-ext-artifacts
|
||||||
|
|
||||||
|
# catchall editor and OS stuff
|
||||||
|
#
|
||||||
|
.tags
|
||||||
|
.etags
|
||||||
|
tags
|
||||||
|
TAGS
|
||||||
|
GPATH
|
||||||
|
GRTAGS
|
||||||
|
GTAGS
|
||||||
|
.DS_Store
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
\#*\#
|
\#*\#
|
||||||
s/*
|
s/*
|
||||||
**/.DS_Store
|
|
||||||
**/dist
|
|
||||||
**/node_modules
|
|
||||||
**/urbitrc
|
|
||||||
**/*.swp
|
|
||||||
**/*.swo
|
|
||||||
**/*-min.js
|
|
||||||
.stack-work
|
|
||||||
pkg/interface/link-webext/web-ext-artifacts
|
|
||||||
|
@ -158,9 +158,8 @@ commit that updates the source.
|
|||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
|
|
||||||
We typically create releases by cherry picking appropriate commits from
|
We typically create releases by tagging appropriate commits on `master`, so any
|
||||||
`master` and tagging the result, so any given commit in `master` may not
|
given commit in `master` may not actually be present in the latest release.
|
||||||
actually be present in the latest release.
|
|
||||||
|
|
||||||
We perform updates by pushing releases over-the-air to `~zod` approximately
|
We perform updates by pushing releases over-the-air to `~zod` approximately
|
||||||
once per week, so any contribution that can be deployed OTA will usually find
|
once per week, so any contribution that can be deployed OTA will usually find
|
||||||
|
247
MAINTAINERS.md
@ -1,13 +1,125 @@
|
|||||||
# Maintainers' Guide
|
# Maintainers' Guide
|
||||||
|
|
||||||
|
## Branch organization
|
||||||
|
|
||||||
|
The essence of this branching scheme is that you create "release branches" of
|
||||||
|
independently releasable units of work. These can then be released by their
|
||||||
|
maintainers when ready.
|
||||||
|
|
||||||
|
### Master branch
|
||||||
|
|
||||||
|
Master is what's released on the network. Deployment instructions are in the
|
||||||
|
next section, but tagged releases should always come from this branch.
|
||||||
|
|
||||||
|
### Feature branches
|
||||||
|
|
||||||
|
Anyone can create feature branches. For those with commit access to
|
||||||
|
urbit/urbit, you're welcome to create them in this repo; otherwise, fork the
|
||||||
|
repo and create them there.
|
||||||
|
|
||||||
|
Usually, new development should start from master, but if your work depends on
|
||||||
|
work in another feature branch or release branch, start from there.
|
||||||
|
|
||||||
|
If, after starting your work, you need changes that are in master, merge it into
|
||||||
|
your branch. If you need changes that are in a release branch or feature
|
||||||
|
branch, merge it into your branch, but understand that your work now depends on
|
||||||
|
that release branch, which means it won't be released until that one is
|
||||||
|
released.
|
||||||
|
|
||||||
|
### Release branches
|
||||||
|
|
||||||
|
Release branches are code that is ready to release. All release branch names
|
||||||
|
should start with `release/`.
|
||||||
|
|
||||||
|
All code must be reviewed before being pushed to a release branch. Thus,
|
||||||
|
feature branches should be PR'd against a release branch, not master.
|
||||||
|
|
||||||
|
Create new release branches as needed. You don't need a new one for every PR,
|
||||||
|
since many changes are relatively small and can be merged together with little
|
||||||
|
risk. However, once you merge two branches, they're now coupled and will only
|
||||||
|
be released together -- unless one of the underlying commits is separately put
|
||||||
|
on a release branch.
|
||||||
|
|
||||||
|
Here's a worked example. The rule is to make however many branches are useful,
|
||||||
|
and no more. This example is not prescriptive, the developers making the
|
||||||
|
changes may add, remove, or rename branches in this flow at will.
|
||||||
|
|
||||||
|
Suppose you (plural, the dev community at large) complete some work in a
|
||||||
|
userspace app, and you put it in `release/next-userspace`. Separately, you make
|
||||||
|
a small JS change. If you PR it to `release/next-userspace`, then it will only
|
||||||
|
be released at the same time as the app changes. Maybe this is fine, or maybe
|
||||||
|
you want this change to go out quickly, and the change in
|
||||||
|
`release/next-userspace` is relatively risky, so you don't want to push it out
|
||||||
|
on Friday afternoon. In this case, put the change in another release branch,
|
||||||
|
say `release/next-js`. Now either can be released independently.
|
||||||
|
|
||||||
|
Suppose you do further work that you want to PR to `release/next-userspace`, but
|
||||||
|
it depends on your fixes in `release/next-js`. Simply merge `release/next-js`
|
||||||
|
into either your feature branch or `release/next-userspace` and PR your finished
|
||||||
|
work to `release/next-userspace`. Now there is a one-way coupling:
|
||||||
|
`release/next-userspace` contains `release/next-js`, so releasing it will
|
||||||
|
implicitly release `release/next-js`. However, you can still release
|
||||||
|
`release/next-js` independently.
|
||||||
|
|
||||||
|
This scheme extends to other branches, like `release/next-kernel` or
|
||||||
|
`release/os1.1` or `release/ford-fusion`. Some branches may be long-lived and
|
||||||
|
represent simply the "next" release of something, while others will have a
|
||||||
|
definite lifetime that corresponds to development of a particular feature or
|
||||||
|
numbered release.
|
||||||
|
|
||||||
|
Since they are "done", release branches should be considered "public", in the
|
||||||
|
sense that others may depend on them at will. Thus, never rebase a release
|
||||||
|
branch.
|
||||||
|
|
||||||
|
When cutting a new release, you can filter branches with `git branch --list
|
||||||
|
'release/*'` or by typing "release/" in the branch filter on Github. This will
|
||||||
|
give you the list of branches which have passed review and may be merged to
|
||||||
|
master and released. When choosing which branches to release, make sure you
|
||||||
|
understand the risks of releasing them immediately. If merging these produces
|
||||||
|
nontrivial conflicts, consider asking the developers on those branches to merge
|
||||||
|
between themselves. In many cases a developer can do this directly, but if it's
|
||||||
|
sufficiently nontrivial, this may be a reviewed PR of one release branch into
|
||||||
|
another.
|
||||||
|
|
||||||
|
### Non-OTAable release branches
|
||||||
|
|
||||||
|
In some cases, work is completed which cannot be OTA'd as written. For example,
|
||||||
|
the code may lack state adapters, or it may not properly handle outstanding
|
||||||
|
subscriptions. It could also be code which is planned to be released only upon
|
||||||
|
a breach (network-wide or rolling).
|
||||||
|
|
||||||
|
In this case, the code may be PR'd to a `na-release/` branch. All rules are the
|
||||||
|
same as for release branches, except that the code does not need to apply
|
||||||
|
cleanly to an existing ship. If you later write state adapter or otherwise make
|
||||||
|
it OTAable, then you may PR it to a release branch.
|
||||||
|
|
||||||
|
### Other cases
|
||||||
|
|
||||||
|
Outside contributors can generally target their PRs against master unless
|
||||||
|
specifically instructed. Maintainers should retarget those branches as
|
||||||
|
appropriate.
|
||||||
|
|
||||||
|
If a commit is not something that goes into a release (eg changes to README or
|
||||||
|
CI), it may be committed straight to master.
|
||||||
|
|
||||||
|
If a hotfix is urgent, it may be PR'd straight to master. This should only be
|
||||||
|
done if you reasonably expect that it will be released soon and before anything
|
||||||
|
else is released.
|
||||||
|
|
||||||
|
If a series of commits that you want to release is on a release branch, but you
|
||||||
|
really don't want to release the whole branch, you must cherry-pick them onto
|
||||||
|
another release branch. Cherry-picking isn't ideal because those commits will
|
||||||
|
be duplicated in the history, but it won't have any serious side effects.
|
||||||
|
|
||||||
|
|
||||||
## Hotfixes
|
## Hotfixes
|
||||||
|
|
||||||
Here lies an informal guide for making hotfix releases and deploying them to
|
Here lies an informal guide for making hotfix releases and deploying them to
|
||||||
the network.
|
the network.
|
||||||
|
|
||||||
Take [this recent PR][1], as an example. This constituted a great hotfix.
|
Take [this PR][1], as an example. This constituted a great hotfix. It's a
|
||||||
It's a single commit, targeting a problem that existed on the network at the
|
single commit, targeting a problem that existed on the network at the time.
|
||||||
time. Here's it should be released and deployed OTA.
|
Here's it should be released and deployed OTA.
|
||||||
|
|
||||||
[1]: https://github.com/urbit/urbit/pull/2025
|
[1]: https://github.com/urbit/urbit/pull/2025
|
||||||
|
|
||||||
@ -16,14 +128,9 @@ time. Here's it should be released and deployed OTA.
|
|||||||
Unless it's very trivial, it should probably have a single "credible looking"
|
Unless it's very trivial, it should probably have a single "credible looking"
|
||||||
review from somebody else on it.
|
review from somebody else on it.
|
||||||
|
|
||||||
You can just merge the PR in GitHub. As I, `~nidsut-tomdun`, am a l33t
|
You should avoid merging the PR in GitHub directly. Instead, use the
|
||||||
h4x0r, I use a custom merge commit format, gotten by:
|
`sh/merge-with-custom-msg` script -- it will produce a merge commit with
|
||||||
|
message along the lines of:
|
||||||
```
|
|
||||||
git merge --no-ff --signoff --log BRANCH
|
|
||||||
```
|
|
||||||
|
|
||||||
with the commit message:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Merge branch FOO (#PR_NUM)
|
Merge branch FOO (#PR_NUM)
|
||||||
@ -32,66 +139,58 @@ Merge branch FOO (#PR_NUM)
|
|||||||
bar: ...
|
bar: ...
|
||||||
baz: ...
|
baz: ...
|
||||||
|
|
||||||
Signed-off-by: Jared Tobin <jared@tlon.io>
|
Signed-off-by: SIGNER <signer@example.com>
|
||||||
```
|
```
|
||||||
|
|
||||||
All this extra wankery is hardly required, but IMO it's nice to have the
|
We do this as it's nice to have the commit log information in the merge commit,
|
||||||
commit log information in the merge commit, which GitHub's "Merge PR" button
|
which GitHub's "Merge PR" button doesn't do (at least by default).
|
||||||
doesn't do (at least by default).
|
`sh/merge-with-custom-msg` performs some useful last-minute urbit-specific
|
||||||
|
checks, as well.
|
||||||
|
|
||||||
The script at `sh/merge-with-custom-message` can be used to make this simple(r)
|
You might want to alias `sh/merge-with-custom-msg` locally, to make it easier
|
||||||
to do. I use `git mu` as an alias for it, locally.
|
to use. My .git/config contains the following, for example:
|
||||||
|
|
||||||
### Apply the changes to this era's release branch
|
|
||||||
|
|
||||||
This corresponds to the 'vx.y' part of the most recent 'urbit vx.y.z' release.
|
|
||||||
At the time of writing, we're on v0.10 (and I'll use this branch as a running
|
|
||||||
example):
|
|
||||||
|
|
||||||
If the branch doesn't yet exist, just create it via:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git checkout -b v0.10 master
|
[alias]
|
||||||
|
mu = !sh/merge-with-custom-msg
|
||||||
```
|
```
|
||||||
|
|
||||||
If you can get away with merging master to v0.10 without pulling in any
|
so that I can type e.g. `git mu origin/foo 1337`.
|
||||||
superfluous commits, feel free to do that. Otherwise, you'll want to cherry
|
|
||||||
pick the commits like so:
|
|
||||||
|
|
||||||
```
|
### Prepare a release commit
|
||||||
git cherry-pick -x TARGET_COMMITS
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the `-x` flag to `git-cherry-pick`, because this will indicate in the
|
You should create Landscape or alternative pill builds, if or as appropriate
|
||||||
commit message where the things originally came from.
|
(i.e., if anything in Landscape changed -- don't trust any compiled JS/CSS
|
||||||
|
that's included in the commit), and commit these in a release commit.
|
||||||
|
|
||||||
Create Landscape or alternative pill builds, if or as appropriate (i.e., if
|
You should always create a solid pill, in particular, as it's convenient for
|
||||||
anything in Landscape changed -- don't trust the compiled JS/CSS that's
|
|
||||||
included in the commit).
|
|
||||||
|
|
||||||
You may also want to create a brass pill, in particular, as it's convenient for
|
|
||||||
tooling to be able to boot directly from a given release.
|
tooling to be able to boot directly from a given release.
|
||||||
|
|
||||||
|
If you're making a Vere release, just play it safe and update all the pills.
|
||||||
|
|
||||||
### Tag the resulting commit
|
### Tag the resulting commit
|
||||||
|
|
||||||
What you should do here depends on the type of release being made.
|
What you should do here depends on the type of release being made.
|
||||||
|
|
||||||
First, for Arvo releases:
|
First, for Urbit OS releases:
|
||||||
|
|
||||||
If it's a very trivial hotfix that you know isn't going to break
|
If it's a very trivial hotfix that you know isn't going to break
|
||||||
anything, tag it as `arvo.yyyy.mm.dd`. Use an annotated tag, i.e.
|
anything, tag it as `urbit-os-vx.y.z`. Here 'x' refers to the product version
|
||||||
|
(e.g. OS1, OS2..), 'y' to the continuity era in that version, and 'z' to an
|
||||||
|
OTA patch counter. So for a hotfix version, you'll just want to increment 'z'.
|
||||||
|
|
||||||
|
Use an annotated tag, i.e.
|
||||||
|
|
||||||
```
|
```
|
||||||
git tag -a arvo.yyyy.mm.dd
|
git tag -a urbit-os-vx.y.z
|
||||||
```
|
```
|
||||||
|
|
||||||
The tag format should look something like this:
|
The tag format should look something like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
arvo.yyyy.mm.dd
|
urbit-os-vx.y.z
|
||||||
|
|
||||||
This release contains Arvo changes that will be pushed to the live
|
This release will be pushed to the network as an over-the-air update.
|
||||||
network as an over-the-air update.
|
|
||||||
|
|
||||||
Release notes:
|
Release notes:
|
||||||
|
|
||||||
@ -106,8 +205,7 @@ You can get the "contributions" section by the shortlog between the
|
|||||||
last release and this release:
|
last release and this release:
|
||||||
|
|
||||||
```
|
```
|
||||||
git log --pretty=short --no-merges \
|
git log --pretty=short LAST_RELEASE.. | git shortlog
|
||||||
LAST_RELEASE..v0.10 | git shortlog
|
|
||||||
```
|
```
|
||||||
|
|
||||||
I originally tried to curate this list somewhat, but now just paste it
|
I originally tried to curate this list somewhat, but now just paste it
|
||||||
@ -121,23 +219,28 @@ If the commit descriptions are too poor to easily do this, then again, yell at
|
|||||||
your fellow contributors to make them better in the future.
|
your fellow contributors to make them better in the future.
|
||||||
|
|
||||||
If it's *not* a trivial hotfix, you should probably make any number of release
|
If it's *not* a trivial hotfix, you should probably make any number of release
|
||||||
candidate tags (e.g. `arvo.yyyy.mm.dd.rc-1`, `arvo.yyyy.mm.dd.rc-2`, ..), test
|
candidate tags (e.g. `urbit-os-vx.y.z.rc1`, `urbit-os-vx.y.z.rc2`, ..), test
|
||||||
them, and after you confirm one of them is good, tag the release as
|
them, and after you confirm one of them is good, tag the release as
|
||||||
`arvo.yyyy.mm.dd`.
|
`urbit-os-vx.y.z`.
|
||||||
|
|
||||||
For Vere releases:
|
For Vere releases:
|
||||||
|
|
||||||
Tag the release as `vx.y.z`. The tag format should look something
|
Tag the release as `urbit-vx.y.z`. The tag format should look something like
|
||||||
like this:
|
this:
|
||||||
|
|
||||||
```
|
```
|
||||||
urbit vx.y.z
|
urbit-vx.y.z
|
||||||
|
|
||||||
This release contains Vere changes, so users should update their
|
Note that this Vere release will by default boot fresh ships using an Urbit OS
|
||||||
binaries.
|
va.b.c pill.
|
||||||
|
|
||||||
This is not a breaching release, so users should not create new
|
Release binaries:
|
||||||
piers.
|
|
||||||
|
(linux64)
|
||||||
|
https://bootstrap.urbit.org/urbit-vx.y.z-linux64.tgz
|
||||||
|
|
||||||
|
(macOS)
|
||||||
|
https://bootstrap.urbit.org/urbit-vx.y.z-darwin.tgz
|
||||||
|
|
||||||
Release notes:
|
Release notes:
|
||||||
|
|
||||||
@ -150,29 +253,37 @@ Contributions:
|
|||||||
|
|
||||||
The same schpeel re: release candidates applies here.
|
The same schpeel re: release candidates applies here.
|
||||||
|
|
||||||
You should probably avoid putting both Arvo and Vere changes into Vere
|
Note that the release notes indicate which version of Urbit OS the Vere release
|
||||||
releases.
|
will use by default when booting fresh ships. Do not include implicit Urbit OS
|
||||||
|
changes in Vere releases; this used to be done, historically, but shouldn't be
|
||||||
|
any longer. If there are Urbit OS and Vere changes to be released, make two
|
||||||
|
separate releases.
|
||||||
|
|
||||||
### Deploy the update
|
### Deploy the update
|
||||||
|
|
||||||
For Arvo updates, this means copying the files into ~zod's %base desk. For
|
(**Note**: the following steps are automated by some other Tlon-internal
|
||||||
consistency, I download the release tarball and then rsync the files in:
|
tooling. Just ask `~nidsut-tomdun` for details.)
|
||||||
|
|
||||||
|
For Urbit OS updates, this means copying the files into ~zod's %base desk. The
|
||||||
|
changes will be synced to /~zod/kids and then propagated through other galaxies
|
||||||
|
and stars to the rest of the network.
|
||||||
|
|
||||||
|
For consistency, I create a release tarball and then rsync the files in.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ wget https://github.com/urbit/urbit/archive/arvo.yyyy.mm.dd.tar.gz
|
$ wget https://github.com/urbit/urbit/archive/urbit-os-vx.y.z.tar.gz
|
||||||
$ tar xzf arvo.yyyy.mm.dd.tar.gz
|
$ tar xzf urbit-os-vx.y.z.tar.gz
|
||||||
$ herb zod -p hood -d "+hood/mount /=base="
|
$ herb zod -p hood -d "+hood/mount /=base="
|
||||||
$ rsync -zr --delete urbit-arvo.yyyy.mm.dd/pkg/arvo/ zod/base
|
$ rsync -zr --delete urbit-urbit-os-vx.y.z/pkg/arvo/ zod/base
|
||||||
$ herb zod -p hood -d "+hood/commit %base"
|
$ herb zod -p hood -d "+hood/commit %base"
|
||||||
```
|
```
|
||||||
|
|
||||||
For Vere updates, this means shutting down each desired ship, installing the
|
For Vere updates, this means simply shutting down each desired ship, installing
|
||||||
new binary, and restarting the pier with it.
|
the new binary, and restarting the pier with it.
|
||||||
|
|
||||||
### Announce the update
|
### Announce the update
|
||||||
|
|
||||||
Post an announcement to urbit-dev. The tag annotation, basically, is fine here
|
Post an announcement to urbit-dev. The tag annotation, basically, is fine here
|
||||||
-- I usually add the %base hash (for Arvo releases) and the release binary URLs
|
-- I usually add the %base hash (for Urbit OS releases) and the release binary
|
||||||
(for Vere releaes). Check the urbit-dev archives for examples of these
|
URLs (for Vere releases). Check the urbit-dev archives for examples of these
|
||||||
announcements.
|
announcements.
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:362ba607d646cc053ef27c9cab1d7e6cf07856d0949cb5a48e17ef536e857613
|
oid sha256:5f283336929733f6492f7fe230c949749cea43c8a1fb18959742b2ff88e9d239
|
||||||
size 7227783
|
size 10418083
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:61a38233c95cd8e0c0790e33c134c1aab607659a16abce22e85f56b6c77b19c5
|
oid sha256:8d2579ed2b72828ced40789c0eae516a832c66f8f9dcd06af4ba5ec4cb4e2ac6
|
||||||
size 1232440
|
size 1236461
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:df7e73129cc484fba44301eec4230b9ec3dc533163db36b885074ff8b018b6c8
|
oid sha256:20219ec89d58a89285733db183b89e5f19e5bb7764bed43218c0c83902dd1e56
|
||||||
size 9650082
|
size 12878034
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
source $stdenv/setup
|
|
||||||
|
|
||||||
cp -r $src ./src
|
|
||||||
chmod -R u+w ./src
|
|
||||||
cd src
|
|
||||||
|
|
||||||
bash ./configure
|
|
||||||
|
|
||||||
make clean
|
|
||||||
make all -j8
|
|
||||||
make test
|
|
||||||
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp ./build/urbit $out/bin/$exename
|
|
||||||
cp ./build/urbit-worker $out/bin/$exename-worker
|
|
@ -27,9 +27,21 @@ let
|
|||||||
inherit name meta;
|
inherit name meta;
|
||||||
exename = name;
|
exename = name;
|
||||||
src = ../../../pkg/urbit;
|
src = ../../../pkg/urbit;
|
||||||
builder = ./builder.sh;
|
|
||||||
nativeBuildInputs = deps ++ vendor;
|
nativeBuildInputs = deps ++ vendor;
|
||||||
|
|
||||||
|
configurePhase = ''
|
||||||
|
bash ./configure
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
make all -j8
|
||||||
|
make test
|
||||||
|
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp ./build/urbit $out/bin/$exename
|
||||||
|
cp ./build/urbit-worker $out/bin/$exename-worker
|
||||||
|
'';
|
||||||
|
|
||||||
# See https://github.com/NixOS/nixpkgs/issues/18995
|
# See https://github.com/NixOS/nixpkgs/issues/18995
|
||||||
hardeningDisable = if debug then [ "all" ] else [];
|
hardeningDisable = if debug then [ "all" ] else [];
|
||||||
|
|
||||||
|
@ -87,8 +87,9 @@
|
|||||||
|= [state=app-state our=ship dap=term]
|
|= [state=app-state our=ship dap=term]
|
||||||
^- card:agent:gall
|
^- card:agent:gall
|
||||||
=/ args=vase !>
|
=/ args=vase !>
|
||||||
:* %watch /[dap]
|
:+ %watch /[dap]
|
||||||
url.state =(%czar (clan:title our)) ~m5
|
^- config:eth-watcher
|
||||||
|
:* url.state =(%czar (clan:title our)) ~m5 ~m30
|
||||||
launch:contracts:azimuth
|
launch:contracts:azimuth
|
||||||
~[azimuth:contracts:azimuth]
|
~[azimuth:contracts:azimuth]
|
||||||
(topics whos.state)
|
(topics whos.state)
|
||||||
|
@ -17,8 +17,15 @@
|
|||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
+$ state
|
::
|
||||||
$: grams=(list mail) :: all messages
|
+$ versioned-state
|
||||||
|
$% state-1
|
||||||
|
state-0
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ state-1
|
||||||
|
$: %1
|
||||||
|
grams=(list mail) :: all messages
|
||||||
known=(set [target serial]) :: known message lookup
|
known=(set [target serial]) :: known message lookup
|
||||||
count=@ud :: (lent grams)
|
count=@ud :: (lent grams)
|
||||||
bound=(map target glyph) :: bound circle glyphs
|
bound=(map target glyph) :: bound circle glyphs
|
||||||
@ -31,11 +38,27 @@
|
|||||||
eny=@uvJ :: entropy
|
eny=@uvJ :: entropy
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
+$ state-0
|
||||||
|
$: grams=(list [[=ship =path] envelope]) :: all messages
|
||||||
|
known=(set [[=ship =path] serial]) :: known message lookup
|
||||||
|
count=@ud :: (lent grams)
|
||||||
|
bound=(map [=ship =path] glyph) :: bound circle glyphs
|
||||||
|
binds=(jug glyph [=ship =path]) :: circle glyph lookup
|
||||||
|
audience=(set [=ship =path]) :: active targets
|
||||||
|
settings=(set term) :: frontend flags
|
||||||
|
width=@ud :: display width
|
||||||
|
timez=(pair ? @ud) :: timezone adjustment
|
||||||
|
cli=state=sole-share:sole-sur :: console state
|
||||||
|
eny=@uvJ :: entropy
|
||||||
|
==
|
||||||
|
::
|
||||||
+$ mail [source=target envelope]
|
+$ mail [source=target envelope]
|
||||||
+$ target [=ship =path]
|
+$ target [in-group=? =ship =path]
|
||||||
::
|
::
|
||||||
+$ glyph char
|
+$ glyph char
|
||||||
++ glyphs "!@#$%^&()-=_+[]\{};'\\:\",.<>?"
|
++ glyphs "!@#$%^&()-=_+[]\{}'\\:\",.<>?"
|
||||||
|
::
|
||||||
|
+$ nu-security ?(%channel %village %village-with-group)
|
||||||
::
|
::
|
||||||
+$ command
|
+$ command
|
||||||
$% [%target (set target)] :: set messaging target
|
$% [%target (set target)] :: set messaging target
|
||||||
@ -44,10 +67,10 @@
|
|||||||
::
|
::
|
||||||
::
|
::
|
||||||
:: create chat
|
:: create chat
|
||||||
[%create rw-security path (unit glyph) (unit ?)]
|
[%create nu-security path (unit glyph) (unit ?)]
|
||||||
[%delete path] :: delete chat
|
[%delete path] :: delete chat
|
||||||
[%invite ?(%r %w %rw) path (set ship)] :: allow
|
[%invite [? path] (set ship)] :: allow
|
||||||
[%banish ?(%r %w %rw) path (set ship)] :: disallow
|
[%banish [? path] (set ship)] :: disallow
|
||||||
::
|
::
|
||||||
[%join target (unit glyph) (unit ?)] :: join target
|
[%join target (unit glyph) (unit ?)] :: join target
|
||||||
[%leave target] :: nuke target
|
[%leave target] :: nuke target
|
||||||
@ -68,8 +91,8 @@
|
|||||||
== ::
|
== ::
|
||||||
::
|
::
|
||||||
--
|
--
|
||||||
=| state
|
=| state-1
|
||||||
=* all-state -
|
=* state -
|
||||||
::
|
::
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
%+ verb |
|
%+ verb |
|
||||||
@ -83,26 +106,22 @@
|
|||||||
::
|
::
|
||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
:- [connect:tc]~
|
=^ cards state (prep:tc ~)
|
||||||
%_ this
|
[cards this]
|
||||||
audience [[our-self:tc /] ~ ~]
|
|
||||||
settings (sy %showtime %notify ~)
|
|
||||||
width 80
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
++ on-save !>(all-state)
|
++ on-save !>(state)
|
||||||
::
|
::
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old-state=vase
|
|= old-state=vase
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
=/ old !<(state old-state)
|
=/ old !<(versioned-state old-state)
|
||||||
=^ cards all-state (prep:tc `old)
|
=^ cards state (prep:tc `old)
|
||||||
[cards this]
|
[cards this]
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
=^ cards all-state
|
=^ cards state
|
||||||
?+ mark (on-poke:def mark vase)
|
?+ mark (on-poke:def mark vase)
|
||||||
%noun (poke-noun:tc !<(* vase))
|
%noun (poke-noun:tc !<(* vase))
|
||||||
%sole-action (poke-sole-action:tc !<(sole-action:sole-sur vase))
|
%sole-action (poke-sole-action:tc !<(sole-action:sole-sur vase))
|
||||||
@ -112,7 +131,7 @@
|
|||||||
++ on-watch
|
++ on-watch
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
=^ cards all-state (peer:tc path)
|
=^ cards state (peer:tc path)
|
||||||
[cards this]
|
[cards this]
|
||||||
::
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
@ -120,14 +139,22 @@
|
|||||||
++ on-agent
|
++ on-agent
|
||||||
|= [=wire =sign:agent:gall]
|
|= [=wire =sign:agent:gall]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
=^ cards all-state
|
=^ cards state
|
||||||
?- -.sign
|
?- -.sign
|
||||||
%poke-ack [- all-state]:(on-agent:def wire sign)
|
%poke-ack [- state]:(on-agent:def wire sign)
|
||||||
%watch-ack [- all-state]:(on-agent:def wire sign)
|
%watch-ack [- state]:(on-agent:def wire sign)
|
||||||
%kick [?:(?=([%chat-store ~] wire) ~[connect:tc] ~) all-state]
|
::
|
||||||
|
%kick
|
||||||
|
:_ state
|
||||||
|
?+ wire ~
|
||||||
|
[%chat-store ~] ~[connect:tc]
|
||||||
|
[%invites ~] ~[connect-invites:tc]
|
||||||
|
==
|
||||||
|
::
|
||||||
%fact
|
%fact
|
||||||
?+ p.cage.sign ~|([%chat-cli-bad-sub-mark wire p.cage.sign] !!)
|
?+ p.cage.sign ~|([%chat-cli-bad-sub-mark wire p.cage.sign] !!)
|
||||||
%chat-update (diff-chat-update:tc wire !<(chat-update q.cage.sign))
|
%chat-update (diff-chat-update:tc wire !<(chat-update q.cage.sign))
|
||||||
|
%invite-update (handle-invite-update:tc !<(invite-update q.cage.sign))
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
[cards this]
|
[cards this]
|
||||||
@ -140,58 +167,104 @@
|
|||||||
:: +prep: setup & state adapter
|
:: +prep: setup & state adapter
|
||||||
::
|
::
|
||||||
++ prep
|
++ prep
|
||||||
|= old=(unit state)
|
|= old=(unit versioned-state)
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?^ old
|
?~ old
|
||||||
:_ u.old
|
=^ cards state
|
||||||
?: (~(has by wex.bowl) [/chat-store our-self %chat-store])
|
%_ catch-up
|
||||||
~
|
audience [[| our-self /] ~ ~]
|
||||||
~[connect]
|
settings (sy %showtime %notify ~)
|
||||||
=^ cards all-state
|
width 80
|
||||||
%_ catch-up
|
==
|
||||||
audience [[our-self /] ~ ~]
|
[[connect connect-invites cards] state]
|
||||||
settings (sy %showtime %notify ~)
|
:- %+ weld
|
||||||
width 80
|
?: (~(has by wex.bowl) [/invites our-self %invite-store]) ~
|
||||||
|
~[connect-invites]
|
||||||
|
?: (~(has by wex.bowl) [/chat-store our-self %chat-store]) ~
|
||||||
|
~[connect]
|
||||||
|
::
|
||||||
|
^- state-1
|
||||||
|
?- -.u.old
|
||||||
|
%1
|
||||||
|
=? width.u.old =(0 width.u.old) 80
|
||||||
|
u.old(bound (~(gas by *(map target glyph)) ~(tap by bound.u.old)))
|
||||||
|
::
|
||||||
|
?(~ ^)
|
||||||
|
:- %1
|
||||||
|
%= u.old
|
||||||
|
grams ~ ::NOTE this only impacts historic message lookup in chat-cli
|
||||||
|
::
|
||||||
|
known
|
||||||
|
^- (set [target serial])
|
||||||
|
%- ~(run in known.u.old)
|
||||||
|
|= [t=[ship path] s=serial]
|
||||||
|
[`target`[| t] s]
|
||||||
|
::
|
||||||
|
bound
|
||||||
|
^- (map target glyph)
|
||||||
|
%- ~(gas by *(map target glyph))
|
||||||
|
%+ turn ~(tap by bound.u.old)
|
||||||
|
|= [t=[ship path] g=glyph]
|
||||||
|
[`target`[| t] g]
|
||||||
|
::
|
||||||
|
binds
|
||||||
|
^- (jug glyph target)
|
||||||
|
%- ~(run by binds.u.old)
|
||||||
|
|= s=(set [ship path])
|
||||||
|
%- ~(run in s)
|
||||||
|
|= t=[ship path]
|
||||||
|
`target`[| t]
|
||||||
|
::
|
||||||
|
audience
|
||||||
|
^- (set target)
|
||||||
|
%- ~(run in audience.u.old)
|
||||||
|
|= t=[ship path]
|
||||||
|
`target`[| t]
|
||||||
==
|
==
|
||||||
[[connect cards] all-state]
|
==
|
||||||
:: +catch-up: process all chat-store state
|
:: +catch-up: process all chat-store state
|
||||||
::
|
::
|
||||||
++ catch-up
|
++ catch-up
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=/ =inbox
|
=/ =inbox
|
||||||
.^ inbox
|
(scry-for inbox %chat-store /all)
|
||||||
%gx
|
|- ^- (quip card _state)
|
||||||
(scot %p our.bowl)
|
?~ inbox [~ state]
|
||||||
%chat-store
|
|
||||||
(scot %da now.bowl)
|
|
||||||
/all/noun
|
|
||||||
==
|
|
||||||
|- ^- (quip card state)
|
|
||||||
?~ inbox [~ all-state]
|
|
||||||
=* path p.n.inbox
|
=* path p.n.inbox
|
||||||
=* mailbox q.n.inbox
|
=* mailbox q.n.inbox
|
||||||
=/ =target (path-to-target path)
|
=/ =target (path-to-target path)
|
||||||
=^ cards-n all-state (read-envelopes target envelopes.mailbox)
|
=^ cards-n state (read-envelopes target (flop envelopes.mailbox))
|
||||||
=^ cards-l all-state $(inbox l.inbox)
|
=^ cards-l state $(inbox l.inbox)
|
||||||
=^ cards-r all-state $(inbox r.inbox)
|
=^ cards-r state $(inbox r.inbox)
|
||||||
[:(weld cards-n cards-l cards-r) all-state]
|
[:(weld cards-n cards-l cards-r) state]
|
||||||
:: +connect: connect to the chat-store
|
:: +connect: connect to the chat-store
|
||||||
::
|
::
|
||||||
++ connect
|
++ connect
|
||||||
^- card
|
^- card
|
||||||
[%pass /chat-store %agent [our-self %chat-store] %watch /updates]
|
[%pass /chat-store %agent [our-self %chat-store] %watch /updates]
|
||||||
::
|
::
|
||||||
|
++ connect-invites
|
||||||
|
^- card
|
||||||
|
[%pass /invites %agent [our.bowl %invite-store] %watch /invitatory/chat]
|
||||||
|
::
|
||||||
++ our-self (name:title our.bowl)
|
++ our-self (name:title our.bowl)
|
||||||
:: +target-to-path: prepend ship to the path
|
:: +target-to-path: prepend ship to the path
|
||||||
::
|
::
|
||||||
++ target-to-path
|
++ target-to-path
|
||||||
|= target
|
|= target
|
||||||
|
%+ weld
|
||||||
|
?:(in-group ~ /~)
|
||||||
[(scot %p ship) path]
|
[(scot %p ship) path]
|
||||||
:: +path-to-target: deduces a target from a mailbox path
|
:: +path-to-target: deduces a target from a mailbox path
|
||||||
::
|
::
|
||||||
++ path-to-target
|
++ path-to-target
|
||||||
|= =path
|
|= =path
|
||||||
^- target
|
^- target
|
||||||
|
=^ in-group path
|
||||||
|
?. ?=([%'~' *] path)
|
||||||
|
[& path]
|
||||||
|
[| t.path]
|
||||||
|
:- in-group
|
||||||
?. ?=([@ @ *] path)
|
?. ?=([@ @ *] path)
|
||||||
::TODO can we safely assert the above?
|
::TODO can we safely assert the above?
|
||||||
~& [%path-without-host path]
|
~& [%path-without-host path]
|
||||||
@ -203,24 +276,24 @@
|
|||||||
::
|
::
|
||||||
++ poke-noun
|
++ poke-noun
|
||||||
|= a=*
|
|= a=*
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?: ?=(%connect a)
|
?: ?=(%connect a)
|
||||||
[[connect ~] all-state]
|
[[connect ~] state]
|
||||||
?: ?=(%catch-up a)
|
?: ?=(%catch-up a)
|
||||||
catch-up
|
catch-up
|
||||||
[~ all-state]
|
[~ state]
|
||||||
:: +poke-sole-action: handle cli input
|
:: +poke-sole-action: handle cli input
|
||||||
::
|
::
|
||||||
++ poke-sole-action
|
++ poke-sole-action
|
||||||
::TODO use id.act to support multiple separate sessions
|
::TODO use id.act to support multiple separate sessions
|
||||||
|= [act=sole-action:sole-sur]
|
|= [act=sole-action:sole-sur]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
(sole:sh-in act)
|
(sole:sh-in act)
|
||||||
:: +peer: accept only cli subscriptions from ourselves
|
:: +peer: accept only cli subscriptions from ourselves
|
||||||
::
|
::
|
||||||
++ peer
|
++ peer
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?. (team:title our-self src.bowl)
|
?. (team:title our-self src.bowl)
|
||||||
~| [%peer-talk-stranger src.bowl]
|
~| [%peer-talk-stranger src.bowl]
|
||||||
!!
|
!!
|
||||||
@ -230,40 +303,48 @@
|
|||||||
:: display a fresh prompt
|
:: display a fresh prompt
|
||||||
:- [prompt:sh-out ~]
|
:- [prompt:sh-out ~]
|
||||||
:: start with fresh sole state
|
:: start with fresh sole state
|
||||||
all-state(state.cli *sole-share:sole-sur)
|
state(state.cli *sole-share:sole-sur)
|
||||||
|
:: +handle-invite-update: get new invites
|
||||||
|
::
|
||||||
|
++ handle-invite-update
|
||||||
|
|= upd=invite-update
|
||||||
|
^- (quip card _state)
|
||||||
|
?+ -.upd [~ state]
|
||||||
|
%invite [[(show-invite:sh-out invite.upd) ~] state]
|
||||||
|
==
|
||||||
:: +diff-chat-update: get new mailboxes & messages
|
:: +diff-chat-update: get new mailboxes & messages
|
||||||
::
|
::
|
||||||
++ diff-chat-update
|
++ diff-chat-update
|
||||||
|= [=wire upd=chat-update]
|
|= [=wire upd=chat-update]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?+ -.upd [~ all-state]
|
?+ -.upd [~ state]
|
||||||
%create (notice-create +.upd)
|
%create (notice-create (path-to-target path.upd))
|
||||||
%delete [[(show-delete:sh-out (path-to-target path.upd)) ~] all-state]
|
%delete [[(show-delete:sh-out (path-to-target path.upd)) ~] state]
|
||||||
%message (read-envelope (path-to-target path.upd) envelope.upd)
|
%message (read-envelope (path-to-target path.upd) envelope.upd)
|
||||||
%messages (read-envelopes (path-to-target path.upd) envelopes.upd)
|
%messages (read-envelopes (path-to-target path.upd) (flop envelopes.upd))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ read-envelopes
|
++ read-envelopes
|
||||||
|= [=target envs=(list envelope)]
|
|= [=target envs=(list envelope)]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?~ envs [~ all-state]
|
?~ envs [~ state]
|
||||||
=^ cards-i all-state (read-envelope target i.envs)
|
=^ cards-i state (read-envelope target i.envs)
|
||||||
=^ cards-t all-state $(envs t.envs)
|
=^ cards-t state $(envs t.envs)
|
||||||
[(weld cards-i cards-t) all-state]
|
[(weld cards-i cards-t) state]
|
||||||
::
|
::
|
||||||
++ notice-create
|
++ notice-create
|
||||||
|= =target
|
|= =target
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=^ cards all-state
|
=^ cards state
|
||||||
?: (~(has by bound) target)
|
?: (~(has by bound) target)
|
||||||
[~ all-state]
|
[~ state]
|
||||||
(bind-default-glyph target)
|
(bind-default-glyph target)
|
||||||
[[(show-create:sh-out target) cards] all-state]
|
[[(show-create:sh-out target) cards] state]
|
||||||
:: +bind-default-glyph: bind to default, or random available
|
:: +bind-default-glyph: bind to default, or random available
|
||||||
::
|
::
|
||||||
++ bind-default-glyph
|
++ bind-default-glyph
|
||||||
|= =target
|
|= =target
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=; =glyph (bind-glyph glyph target)
|
=; =glyph (bind-glyph glyph target)
|
||||||
|^ =/ g=glyph (choose glyphs)
|
|^ =/ g=glyph (choose glyphs)
|
||||||
?. (~(has by binds) g) g
|
?. (~(has by binds) g) g
|
||||||
@ -281,7 +362,7 @@
|
|||||||
::
|
::
|
||||||
++ bind-glyph
|
++ bind-glyph
|
||||||
|= [=glyph =target]
|
|= [=glyph =target]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
::TODO should send these to settings store eventually
|
::TODO should send these to settings store eventually
|
||||||
:: if the target was already bound to another glyph, un-bind that
|
:: if the target was already bound to another glyph, un-bind that
|
||||||
::
|
::
|
||||||
@ -289,16 +370,16 @@
|
|||||||
(~(del ju binds) (~(got by bound) target) target)
|
(~(del ju binds) (~(got by bound) target) target)
|
||||||
=. bound (~(put by bound) target glyph)
|
=. bound (~(put by bound) target glyph)
|
||||||
=. binds (~(put ju binds) glyph target)
|
=. binds (~(put ju binds) glyph target)
|
||||||
[(show-glyph:sh-out glyph `target) all-state]
|
[(show-glyph:sh-out glyph `target) state]
|
||||||
:: +unbind-glyph: remove all binding for glyph
|
:: +unbind-glyph: remove all binding for glyph
|
||||||
::
|
::
|
||||||
++ unbind-glyph
|
++ unbind-glyph
|
||||||
|= [=glyph targ=(unit target)]
|
|= [=glyph targ=(unit target)]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?^ targ
|
?^ targ
|
||||||
=. binds (~(del ju binds) glyph u.targ)
|
=. binds (~(del ju binds) glyph u.targ)
|
||||||
=. bound (~(del by bound) u.targ)
|
=. bound (~(del by bound) u.targ)
|
||||||
[(show-glyph:sh-out glyph ~) all-state]
|
[(show-glyph:sh-out glyph ~) state]
|
||||||
=/ ole=(set target)
|
=/ ole=(set target)
|
||||||
(~(get ju binds) glyph)
|
(~(get ju binds) glyph)
|
||||||
=. binds (~(del by binds) glyph)
|
=. binds (~(del by binds) glyph)
|
||||||
@ -308,7 +389,7 @@
|
|||||||
=. bound $(ole l.ole)
|
=. bound $(ole l.ole)
|
||||||
=. bound $(ole r.ole)
|
=. bound $(ole r.ole)
|
||||||
(~(del by bound) n.ole)
|
(~(del by bound) n.ole)
|
||||||
[(show-glyph:sh-out glyph ~) all-state]
|
[(show-glyph:sh-out glyph ~) state]
|
||||||
:: +decode-glyph: find the target that matches a glyph, if any
|
:: +decode-glyph: find the target that matches a glyph, if any
|
||||||
::
|
::
|
||||||
++ decode-glyph
|
++ decode-glyph
|
||||||
@ -331,12 +412,12 @@
|
|||||||
::
|
::
|
||||||
++ read-envelope
|
++ read-envelope
|
||||||
|= [=target =envelope]
|
|= [=target =envelope]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?: (~(has in known) [target uid.envelope])
|
?: (~(has in known) [target uid.envelope])
|
||||||
::NOTE we no-op only because edits aren't possible
|
::NOTE we no-op only because edits aren't possible
|
||||||
[~ all-state]
|
[~ state]
|
||||||
:- (show-envelope:sh-out target envelope)
|
:- (show-envelope:sh-out target envelope)
|
||||||
%_ all-state
|
%_ state
|
||||||
known (~(put in known) [target uid.envelope])
|
known (~(put in known) [target uid.envelope])
|
||||||
grams [[target envelope] grams]
|
grams [[target envelope] grams]
|
||||||
count +(count)
|
count +(count)
|
||||||
@ -351,10 +432,10 @@
|
|||||||
::
|
::
|
||||||
++ sole
|
++ sole
|
||||||
|= act=sole-action:sole-sur
|
|= act=sole-action:sole-sur
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?- -.dat.act
|
?- -.dat.act
|
||||||
%det (edit +.dat.act)
|
%det (edit +.dat.act)
|
||||||
%clr [~ all-state]
|
%clr [~ state]
|
||||||
%ret obey
|
%ret obey
|
||||||
%tab (tab +.dat.act)
|
%tab (tab +.dat.act)
|
||||||
==
|
==
|
||||||
@ -367,8 +448,8 @@
|
|||||||
::
|
::
|
||||||
[%create leaf+";create [type] /chat-name (glyph)"]
|
[%create leaf+";create [type] /chat-name (glyph)"]
|
||||||
[%delete leaf+";delete /chat-name"]
|
[%delete leaf+";delete /chat-name"]
|
||||||
[%invite leaf+";invite [rw | r | w] /chat-name ~ships"]
|
[%invite leaf+";invite /chat-name ~ships"]
|
||||||
[%banish leaf+";banish [rw | r | w] /chat-name ~ships"]
|
[%banish leaf+";banish /chat-name ~ships"]
|
||||||
::
|
::
|
||||||
[%bind leaf+";bind [glyph] ~ship/chat-name"]
|
[%bind leaf+";bind [glyph] ~ship/chat-name"]
|
||||||
[%unbind leaf+";unbind [glyph]"]
|
[%unbind leaf+";unbind [glyph]"]
|
||||||
@ -383,18 +464,18 @@
|
|||||||
==
|
==
|
||||||
++ tab
|
++ tab
|
||||||
|= pos=@ud
|
|= pos=@ud
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?: ?| =(~ buf.state.cli)
|
?: ?| =(~ buf.state.cli)
|
||||||
!=(';' -.buf.state.cli)
|
!=(';' -.buf.state.cli)
|
||||||
==
|
==
|
||||||
:_ all-state
|
:_ state
|
||||||
[(effect:sh-out [%bel ~]) ~]
|
[(effect:sh-out [%bel ~]) ~]
|
||||||
::
|
::
|
||||||
=+ (get-id:auto pos (tufa buf.state.cli))
|
=+ (get-id:auto pos (tufa buf.state.cli))
|
||||||
=/ needle=term
|
=/ needle=term
|
||||||
(fall id '')
|
(fall id '')
|
||||||
?: &(!=(pos 1) =(0 (met 3 needle)))
|
?: &(!=(pos 1) =(0 (met 3 needle)))
|
||||||
[~ all-state] :: autocomplete empty command iff user at start of command
|
[~ state] :: autocomplete empty command iff user at start of command
|
||||||
=/ options=(list (option:auto tank))
|
=/ options=(list (option:auto tank))
|
||||||
(search-prefix:auto needle tab-list)
|
(search-prefix:auto needle tab-list)
|
||||||
=/ advance=term
|
=/ advance=term
|
||||||
@ -407,9 +488,9 @@
|
|||||||
=? moves ?=(^ options)
|
=? moves ?=(^ options)
|
||||||
[(tab:sh-out options) moves]
|
[(tab:sh-out options) moves]
|
||||||
=| fxs=(list sole-effect:sole-sur)
|
=| fxs=(list sole-effect:sole-sur)
|
||||||
|- ^- (quip card state)
|
|- ^- (quip card _state)
|
||||||
?~ to-send
|
?~ to-send
|
||||||
[(flop moves) all-state]
|
[(flop moves) state]
|
||||||
=^ char state.cli
|
=^ char state.cli
|
||||||
(~(transmit sole-lib state.cli) [%ins send-pos `@c`i.to-send])
|
(~(transmit sole-lib state.cli) [%ins send-pos `@c`i.to-send])
|
||||||
%_ $
|
%_ $
|
||||||
@ -424,17 +505,17 @@
|
|||||||
::
|
::
|
||||||
++ edit
|
++ edit
|
||||||
|= cal=sole-change:sole-sur
|
|= cal=sole-change:sole-sur
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=^ inv state.cli (~(transceive sole-lib state.cli) cal)
|
=^ inv state.cli (~(transceive sole-lib state.cli) cal)
|
||||||
=+ fix=(sanity inv buf.state.cli)
|
=+ fix=(sanity inv buf.state.cli)
|
||||||
?~ lit.fix
|
?~ lit.fix
|
||||||
[~ all-state]
|
[~ state]
|
||||||
:: just capital correction
|
:: just capital correction
|
||||||
?~ err.fix
|
?~ err.fix
|
||||||
(slug fix)
|
(slug fix)
|
||||||
:: allow interior edits and deletes
|
:: allow interior edits and deletes
|
||||||
?. &(?=($del -.inv) =(+(p.inv) (lent buf.state.cli)))
|
?. &(?=($del -.inv) =(+(p.inv) (lent buf.state.cli)))
|
||||||
[~ all-state]
|
[~ state]
|
||||||
(slug fix)
|
(slug fix)
|
||||||
:: +sanity: check input sanity
|
:: +sanity: check input sanity
|
||||||
::
|
::
|
||||||
@ -451,13 +532,13 @@
|
|||||||
::
|
::
|
||||||
++ slug
|
++ slug
|
||||||
|= [lit=(list sole-edit:sole-sur) err=(unit @u)]
|
|= [lit=(list sole-edit:sole-sur) err=(unit @u)]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
?~ lit [~ all-state]
|
?~ lit [~ state]
|
||||||
=^ lic state.cli
|
=^ lic state.cli
|
||||||
%- ~(transmit sole-lib state.cli)
|
%- ~(transmit sole-lib state.cli)
|
||||||
^- sole-edit:sole-sur
|
^- sole-edit:sole-sur
|
||||||
?~(t.lit i.lit [%mor lit])
|
?~(t.lit i.lit [%mor lit])
|
||||||
:_ all-state
|
:_ state
|
||||||
:_ ~
|
:_ ~
|
||||||
%+ effect:sh-out %mor
|
%+ effect:sh-out %mor
|
||||||
:- [%det lic]
|
:- [%det lic]
|
||||||
@ -484,8 +565,8 @@
|
|||||||
==
|
==
|
||||||
==
|
==
|
||||||
;~((glue ace) (tag %delete) path)
|
;~((glue ace) (tag %delete) path)
|
||||||
;~((glue ace) (tag %invite) rw path ships)
|
;~((glue ace) (tag %invite) tarx ships)
|
||||||
;~((glue ace) (tag %banish) rw path ships)
|
;~((glue ace) (tag %banish) tarx ships)
|
||||||
::
|
::
|
||||||
;~ (glue ace)
|
;~ (glue ace)
|
||||||
(tag %join)
|
(tag %join)
|
||||||
@ -505,6 +586,7 @@
|
|||||||
;~((glue ace) (tag %set) flag)
|
;~((glue ace) (tag %set) flag)
|
||||||
;~((glue ace) (tag %unset) flag)
|
;~((glue ace) (tag %unset) flag)
|
||||||
;~(plug (cold %width (jest 'set width ')) dem:ag)
|
;~(plug (cold %width (jest 'set width ')) dem:ag)
|
||||||
|
::
|
||||||
;~ plug
|
;~ plug
|
||||||
(cold %timezone (jest 'set timezone '))
|
(cold %timezone (jest 'set timezone '))
|
||||||
;~ pose
|
;~ pose
|
||||||
@ -551,10 +633,20 @@
|
|||||||
::
|
::
|
||||||
++ tag |*(a=@tas (cold a (jest a))) ::TODO into stdlib
|
++ tag |*(a=@tas (cold a (jest a))) ::TODO into stdlib
|
||||||
++ ship ;~(pfix sig fed:ag)
|
++ ship ;~(pfix sig fed:ag)
|
||||||
++ path ;~(pfix net (most net urs:ab))
|
++ path ;~(pfix net ;~(plug urs:ab (easy ~))) ::NOTE short only, tmp
|
||||||
|
:: +mang: un/managed indicator prefix
|
||||||
|
::
|
||||||
|
++ mang
|
||||||
|
;~ pose
|
||||||
|
(cold %| (jest '~/'))
|
||||||
|
(cold %& (easy ~))
|
||||||
|
==
|
||||||
:: +tarl: local target, as /path
|
:: +tarl: local target, as /path
|
||||||
::
|
::
|
||||||
++ tarl (stag our-self path)
|
++ tarl (stag our-self path)
|
||||||
|
:: +tarx: local target, maybe managed
|
||||||
|
::
|
||||||
|
++ tarx ;~(plug mang path)
|
||||||
:: +tarp: sponsor target, as ^/path
|
:: +tarp: sponsor target, as ^/path
|
||||||
::
|
::
|
||||||
++ tarp
|
++ tarp
|
||||||
@ -564,9 +656,15 @@
|
|||||||
::
|
::
|
||||||
++ targ
|
++ targ
|
||||||
;~ pose
|
;~ pose
|
||||||
tarl
|
;~ plug
|
||||||
tarp
|
mang
|
||||||
;~(plug ship path)
|
::
|
||||||
|
;~ pose
|
||||||
|
tarl
|
||||||
|
tarp
|
||||||
|
;~(plug ship path)
|
||||||
|
==
|
||||||
|
==
|
||||||
(sear decode-glyph glyph)
|
(sear decode-glyph glyph)
|
||||||
==
|
==
|
||||||
:: +tars: set of comma-separated targs
|
:: +tars: set of comma-separated targs
|
||||||
@ -583,11 +681,7 @@
|
|||||||
:: +security: security mode
|
:: +security: security mode
|
||||||
::
|
::
|
||||||
++ security
|
++ security
|
||||||
(perk %channel %village %journal %mailbox ~)
|
(perk %channel %village-with-group %village ~)
|
||||||
:: +rw: read, write, or read-write
|
|
||||||
::
|
|
||||||
++ rw
|
|
||||||
(perk %rw %r %w ~)
|
|
||||||
::
|
::
|
||||||
:: +glyph: shorthand character
|
:: +glyph: shorthand character
|
||||||
::
|
::
|
||||||
@ -654,16 +748,16 @@
|
|||||||
:: the command (if any) gets echoed to the user.
|
:: the command (if any) gets echoed to the user.
|
||||||
::
|
::
|
||||||
++ obey
|
++ obey
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=+ buf=buf.state.cli
|
=+ buf=buf.state.cli
|
||||||
=+ fix=(sanity [%nop ~] buf)
|
=+ fix=(sanity [%nop ~] buf)
|
||||||
?^ lit.fix
|
?^ lit.fix
|
||||||
(slug fix)
|
(slug fix)
|
||||||
=+ jub=(rust (tufa buf) read)
|
=+ jub=(rust (tufa buf) read)
|
||||||
?~ jub [[(effect:sh-out %bel ~) ~] all-state]
|
?~ jub [[(effect:sh-out %bel ~) ~] state]
|
||||||
=^ cal state.cli (~(transmit sole-lib state.cli) [%set ~])
|
=^ cal state.cli (~(transmit sole-lib state.cli) [%set ~])
|
||||||
=^ cards all-state (work u.jub)
|
=^ cards state (work u.jub)
|
||||||
:_ all-state
|
:_ state
|
||||||
%+ weld
|
%+ weld
|
||||||
^- (list card)
|
^- (list card)
|
||||||
:: echo commands into scrollback
|
:: echo commands into scrollback
|
||||||
@ -678,7 +772,7 @@
|
|||||||
::
|
::
|
||||||
++ work
|
++ work
|
||||||
|= job=command
|
|= job=command
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
|^ ?- -.job
|
|^ ?- -.job
|
||||||
%target (set-target +.job)
|
%target (set-target +.job)
|
||||||
%say (say +.job)
|
%say (say +.job)
|
||||||
@ -735,153 +829,145 @@
|
|||||||
:^ %invite /chat
|
:^ %invite /chat
|
||||||
(shax (jam [our-self where] who))
|
(shax (jam [our-self where] who))
|
||||||
^- invite
|
^- invite
|
||||||
=; desc=cord
|
[our-self %chat-hook where who '']
|
||||||
[our-self %chat-hook where who desc]
|
|
||||||
%- crip
|
|
||||||
%+ weld
|
|
||||||
"You have been invited to chat at "
|
|
||||||
~(full tr [our-self where])
|
|
||||||
==
|
==
|
||||||
:: +set-target: set audience, update prompt
|
:: +set-target: set audience, update prompt
|
||||||
::
|
::
|
||||||
++ set-target
|
++ set-target
|
||||||
|= tars=(set target)
|
|= tars=(set target)
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=. audience tars
|
=. audience tars
|
||||||
[[prompt:sh-out ~] all-state]
|
[[prompt:sh-out ~] state]
|
||||||
:: +create: new local mailbox
|
:: +create: new local mailbox
|
||||||
::
|
::
|
||||||
++ create
|
++ create
|
||||||
|= [security=rw-security =path gyf=(unit char) allow-history=(unit ?)]
|
|= [security=nu-security =path gyf=(unit char) allow-history=(unit ?)]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
::TODO check if already exists
|
=/ with-group=? ?=(%village-with-group security)
|
||||||
=/ =target [our-self path]
|
=/ =target [with-group our-self path]
|
||||||
|
=/ real-path=^path (target-to-path target)
|
||||||
|
=/ =rw-security
|
||||||
|
?- security
|
||||||
|
%channel %channel
|
||||||
|
?(%village %village-with-group) %village
|
||||||
|
==
|
||||||
|
?^ (scry-for (unit mailbox) %chat-store [%mailbox real-path])
|
||||||
|
=- [[- ~] state]
|
||||||
|
%- print:sh-out
|
||||||
|
"{(spud path)} already exists!"
|
||||||
=. audience [target ~ ~]
|
=. audience [target ~ ~]
|
||||||
=^ moz all-state
|
=^ moz state
|
||||||
?. ?=(^ gyf) [~ all-state]
|
?. ?=(^ gyf) [~ state]
|
||||||
(bind-glyph u.gyf target)
|
(bind-glyph u.gyf target)
|
||||||
=- [[- moz] all-state]
|
=- [[- moz] state]
|
||||||
%^ act %do-create %chat-view
|
%^ act %do-create %chat-view
|
||||||
:- %chat-view-action
|
:- %chat-view-action
|
||||||
!>
|
!> ^- chat-view-action
|
||||||
:* %create
|
:* %create
|
||||||
path
|
(rsh 3 1 (spat path))
|
||||||
security
|
''
|
||||||
:: ensure we can read from/write to our own chats
|
real-path :: chat
|
||||||
::
|
real-path :: group
|
||||||
:: read
|
rw-security
|
||||||
?- security
|
~
|
||||||
?(%channel %journal) ~
|
|
||||||
?(%village %mailbox) [our-self ~ ~]
|
|
||||||
==
|
|
||||||
:: write
|
|
||||||
?- security
|
|
||||||
?(%channel %mailbox) ~
|
|
||||||
?(%village %journal) [our-self ~ ~]
|
|
||||||
==
|
|
||||||
(fall allow-history %.y)
|
(fall allow-history %.y)
|
||||||
==
|
==
|
||||||
:: +delete: delete local chats
|
:: +delete: delete local chats
|
||||||
::
|
::
|
||||||
++ delete
|
++ delete
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=- [[- ~] all-state]
|
=- [[- ~] state]
|
||||||
%^ act %do-delete %chat-view
|
%^ act %do-delete %chat-view
|
||||||
:- %chat-view-action
|
:- %chat-view-action
|
||||||
!>
|
!> ^- chat-view-action
|
||||||
[%delete (target-to-path our-self path)]
|
[%delete (target-to-path | our-self path)]
|
||||||
:: +change-permission: modify permissions on a local chat
|
:: +change-permission: modify permissions on a local chat
|
||||||
::
|
::
|
||||||
++ change-permission
|
++ change-permission
|
||||||
|= [allow=? rw=?(%r %w %rw) =path ships=(set ship)]
|
|= [allow=? [group=? =path] ships=(set ship)]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
:_ all-state
|
:_ state
|
||||||
=; cards=(list card)
|
=/ real-path=^path
|
||||||
?. allow cards
|
(target-to-path group our-self path)
|
||||||
%+ weld cards
|
=; permit=(unit card)
|
||||||
%+ turn ~(tap in ships)
|
%+ weld (drop permit)
|
||||||
(cury invite-card path)
|
?. allow ~
|
||||||
%+ murn
|
^- (list card)
|
||||||
^- (list term)
|
%+ murn ~(tap in ships)
|
||||||
?- rw
|
|= =ship
|
||||||
%r [%read ~]
|
^- (unit card)
|
||||||
%w [%write ~]
|
:: if they weren't permitted before, some hook will send an invite.
|
||||||
%rw [%read %write ~]
|
:: but if they already were, we want to send an invite ourselves.
|
||||||
==
|
::
|
||||||
|= =term
|
?. %^ scry-for ?
|
||||||
^- (unit card)
|
%permission-store
|
||||||
=. path
|
[%permitted (scot %p ship) real-path]
|
||||||
=- (snoc `^path`- term)
|
~
|
||||||
[%chat (target-to-path our-self path)]
|
`(invite-card real-path ship)
|
||||||
:: whitelist: empty if no matching permission, else true if whitelist
|
:: whitelist: empty if no matching permission, else true if whitelist
|
||||||
::
|
::
|
||||||
=/ whitelist=(unit ?)
|
=/ whitelist=(unit ?)
|
||||||
=; perm=(unit permission)
|
=; perm=(unit permission)
|
||||||
?~(perm ~ `?=(%white kind.u.perm))
|
?~(perm ~ `?=(%white kind.u.perm))
|
||||||
::TODO +permission-of-target?
|
::TODO +permission-of-target?
|
||||||
.^ (unit permission)
|
%^ scry-for (unit permission)
|
||||||
%gx
|
%permission-store
|
||||||
(scot %p our-self)
|
[%permission real-path]
|
||||||
%permission-store
|
|
||||||
(scot %da now.bowl)
|
|
||||||
%permission
|
|
||||||
(snoc path %noun)
|
|
||||||
==
|
|
||||||
?~ whitelist
|
?~ whitelist
|
||||||
~& [%weird-no-permission path]
|
~& [%weird-no-permission real-path]
|
||||||
~
|
~
|
||||||
%- some
|
%- some
|
||||||
%^ act %do-permission %group-store
|
%^ act %do-permission %group-store
|
||||||
:- %group-action
|
:- %group-action
|
||||||
!>
|
!> ^- group-action
|
||||||
?: =(u.whitelist allow)
|
?: =(u.whitelist allow)
|
||||||
[%add ships path]
|
[%add ships real-path]
|
||||||
[%remove ships path]
|
[%remove ships real-path]
|
||||||
:: +join: sync with remote mailbox
|
:: +join: sync with remote mailbox
|
||||||
::
|
::
|
||||||
++ join
|
++ join
|
||||||
|= [=target gyf=(unit char) ask-history=(unit ?)]
|
|= [=target gyf=(unit char) ask-history=(unit ?)]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=^ moz all-state
|
=^ moz state
|
||||||
?. ?=(^ gyf) [~ all-state]
|
?. ?=(^ gyf) [~ state]
|
||||||
(bind-glyph u.gyf target)
|
(bind-glyph u.gyf target)
|
||||||
=. audience [target ~ ~]
|
=. audience [target ~ ~]
|
||||||
=; =card
|
=; =card
|
||||||
[[card prompt:sh-out moz] all-state]
|
[[card prompt:sh-out moz] state]
|
||||||
::TODO ideally we'd check permission first. attempting this and failing
|
::TODO ideally we'd check permission first. attempting this and failing
|
||||||
:: gives ugly %chat-hook-reap
|
:: gives ugly %chat-hook-reap
|
||||||
%^ act %do-join %chat-view
|
%^ act %do-join %chat-view
|
||||||
:- %chat-view-action
|
:- %chat-view-action
|
||||||
!>
|
!> ^- chat-view-action
|
||||||
[%join ship.target path.target (fall ask-history %.y)]
|
[%join ship.target (target-to-path target) (fall ask-history %.y)]
|
||||||
:: +leave: unsync & destroy mailbox
|
:: +leave: unsync & destroy mailbox
|
||||||
::
|
::
|
||||||
::TODO allow us to "mute" local chats using this
|
::TODO allow us to "mute" local chats using this
|
||||||
++ leave
|
++ leave
|
||||||
|= =target
|
|= =target
|
||||||
=- [[- ~] all-state]
|
=- [[- ~] state]
|
||||||
?: =(our-self ship.target)
|
?: =(our-self ship.target)
|
||||||
%- print:sh-out
|
%- print:sh-out
|
||||||
"can't ;leave local chats, maybe use ;delete instead"
|
"can't ;leave local chats, maybe use ;delete instead"
|
||||||
%^ act %do-leave %chat-hook
|
%^ act %do-leave %chat-hook
|
||||||
:- %chat-hook-action
|
:- %chat-hook-action
|
||||||
!>
|
!> ^- chat-hook-action
|
||||||
[%remove (target-to-path target)]
|
[%remove (target-to-path target)]
|
||||||
:: +say: send messages
|
:: +say: send messages
|
||||||
::
|
::
|
||||||
++ say
|
++ say
|
||||||
|= =letter
|
|= =letter
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
~! bowl
|
~! bowl
|
||||||
=/ =serial (shaf %msg-uid eny.bowl)
|
=/ =serial (shaf %msg-uid eny.bowl)
|
||||||
:_ all-state(eny (shax eny.bowl))
|
:_ state(eny (shax eny.bowl))
|
||||||
^- (list card)
|
^- (list card)
|
||||||
%+ turn ~(tap in audience)
|
%+ turn ~(tap in audience)
|
||||||
|= =target
|
|= =target
|
||||||
%^ act %out-message %chat-hook
|
%^ act %out-message %chat-hook
|
||||||
:- %chat-action
|
:- %chat-action
|
||||||
!>
|
!> ^- chat-action
|
||||||
:+ %message (target-to-path target)
|
:+ %message (target-to-path target)
|
||||||
[serial *@ our-self now.bowl letter]
|
[serial *@ our-self now.bowl letter]
|
||||||
:: +eval: run hoon, send code and result as message
|
:: +eval: run hoon, send code and result as message
|
||||||
@ -895,8 +981,8 @@
|
|||||||
::
|
::
|
||||||
++ lookup-glyph
|
++ lookup-glyph
|
||||||
|= qur=(unit $@(glyph target))
|
|= qur=(unit $@(glyph target))
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=- [[- ~] all-state]
|
=- [[- ~] state]
|
||||||
?^ qur
|
?^ qur
|
||||||
?^ u.qur
|
?^ u.qur
|
||||||
=+ gyf=(~(get by bound) u.qur)
|
=+ gyf=(~(get by bound) u.qur)
|
||||||
@ -920,8 +1006,8 @@
|
|||||||
:: +show-settings: print enabled flags, timezone and width settings
|
:: +show-settings: print enabled flags, timezone and width settings
|
||||||
::
|
::
|
||||||
++ show-settings
|
++ show-settings
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
:_ all-state
|
:_ state
|
||||||
:~ %- print:sh-out
|
:~ %- print:sh-out
|
||||||
%- zing
|
%- zing
|
||||||
^- (list tape)
|
^- (list tape)
|
||||||
@ -941,24 +1027,24 @@
|
|||||||
::
|
::
|
||||||
++ set-setting
|
++ set-setting
|
||||||
|= =term
|
|= =term
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
[~ all-state(settings (~(put in settings) term))]
|
[~ state(settings (~(put in settings) term))]
|
||||||
:: +unset-setting: disable settings flag
|
:: +unset-setting: disable settings flag
|
||||||
::
|
::
|
||||||
++ unset-setting
|
++ unset-setting
|
||||||
|= =term
|
|= =term
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
[~ all-state(settings (~(del in settings) term))]
|
[~ state(settings (~(del in settings) term))]
|
||||||
:: +set-width: configure cli printing width
|
:: +set-width: configure cli printing width
|
||||||
::
|
::
|
||||||
++ set-width
|
++ set-width
|
||||||
|= w=@ud
|
|= w=@ud
|
||||||
[~ all-state(width w)]
|
[~ state(width w)]
|
||||||
:: +set-timezone: configure timestamp printing adjustment
|
:: +set-timezone: configure timestamp printing adjustment
|
||||||
::
|
::
|
||||||
++ set-timezone
|
++ set-timezone
|
||||||
|= tz=[? @ud]
|
|= tz=[? @ud]
|
||||||
[~ all-state(timez tz)]
|
[~ state(timez tz)]
|
||||||
:: +select: expand message from number reference
|
:: +select: expand message from number reference
|
||||||
::
|
::
|
||||||
++ select
|
++ select
|
||||||
@ -967,7 +1053,7 @@
|
|||||||
:: (with leading zeros used for precision)
|
:: (with leading zeros used for precision)
|
||||||
::
|
::
|
||||||
|= num=$@(rel=@ud [zeros=@u abs=@ud])
|
|= num=$@(rel=@ud [zeros=@u abs=@ud])
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
|^ ?@ num
|
|^ ?@ num
|
||||||
=+ tum=(scow %s (new:si | +(num)))
|
=+ tum=(scow %s (new:si | +(num)))
|
||||||
?: (gte rel.num count)
|
?: (gte rel.num count)
|
||||||
@ -985,7 +1071,7 @@
|
|||||||
::
|
::
|
||||||
++ just-print
|
++ just-print
|
||||||
|= txt=tape
|
|= txt=tape
|
||||||
[[(print:sh-out txt) ~] all-state]
|
[[(print:sh-out txt) ~] state]
|
||||||
:: +index: get message index from absolute reference
|
:: +index: get message index from absolute reference
|
||||||
::
|
::
|
||||||
++ index
|
++ index
|
||||||
@ -999,10 +1085,10 @@
|
|||||||
::
|
::
|
||||||
++ activate
|
++ activate
|
||||||
|= [number=tape index=@ud]
|
|= [number=tape index=@ud]
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=+ gam=(snag index grams)
|
=+ gam=(snag index grams)
|
||||||
=. audience [source.gam ~ ~]
|
=. audience [source.gam ~ ~]
|
||||||
:_ all-state
|
:_ state
|
||||||
^- (list card)
|
^- (list card)
|
||||||
:~ (print:sh-out ['?' ' ' number])
|
:~ (print:sh-out ['?' ' ' number])
|
||||||
(effect:sh-out ~(render-activate mr gam))
|
(effect:sh-out ~(render-activate mr gam))
|
||||||
@ -1012,17 +1098,14 @@
|
|||||||
:: +chats: display list of local mailboxes
|
:: +chats: display list of local mailboxes
|
||||||
::
|
::
|
||||||
++ chats
|
++ chats
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
:_ all-state
|
:_ state
|
||||||
:_ ~
|
:_ ~
|
||||||
%- print-more:sh-out
|
%- print-more:sh-out
|
||||||
=/ all
|
=/ all
|
||||||
::TODO refactor
|
%^ scry-for (set path)
|
||||||
::TODO remote scries fail... but moon support?
|
%chat-store
|
||||||
.^ (set path)
|
/keys
|
||||||
%gx
|
|
||||||
/(scot %p our-self)/chat-store/(scot %da now.bowl)/keys/noun
|
|
||||||
==
|
|
||||||
%+ turn ~(tap in all)
|
%+ turn ~(tap in all)
|
||||||
%+ cork path-to-target
|
%+ cork path-to-target
|
||||||
|= target
|
|= target
|
||||||
@ -1030,8 +1113,8 @@
|
|||||||
:: +help: print (link to) usage instructions
|
:: +help: print (link to) usage instructions
|
||||||
::
|
::
|
||||||
++ help
|
++ help
|
||||||
^- (quip card state)
|
^- (quip card _state)
|
||||||
=- [[- ~] all-state]
|
=- [[- ~] state]
|
||||||
(print:sh-out "see https://urbit.org/using/operations/using-your-ship/#messaging")
|
(print:sh-out "see https://urbit.org/using/operations/using-your-ship/#messaging")
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
@ -1148,6 +1231,14 @@
|
|||||||
%+ weld "set: {[glyph ~]} "
|
%+ weld "set: {[glyph ~]} "
|
||||||
?~ target "unbound"
|
?~ target "unbound"
|
||||||
~(phat tr u.target)
|
~(phat tr u.target)
|
||||||
|
:: +show-invite: print incoming invite notification
|
||||||
|
::
|
||||||
|
++ show-invite
|
||||||
|
|= invite
|
||||||
|
^- card
|
||||||
|
%- note
|
||||||
|
%+ weld "invited to: "
|
||||||
|
~(phat tr (path-to-target path))
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
:: +tr: render targets
|
:: +tr: render targets
|
||||||
@ -1181,17 +1272,21 @@
|
|||||||
::
|
::
|
||||||
++ full
|
++ full
|
||||||
^- tape
|
^- tape
|
||||||
(weld (scow %p ship.one) (spud path.one))
|
;: weld
|
||||||
|
?:(in-group.one "" "~/")
|
||||||
|
(scow %p ship.one)
|
||||||
|
(spud path.one)
|
||||||
|
==
|
||||||
:: +phat: render target with local shorthand
|
:: +phat: render target with local shorthand
|
||||||
::
|
::
|
||||||
:: renders as ~ship/path.
|
:: renders as ~ship/path.
|
||||||
:: for local mailboxes, renders just /path.
|
:: for local mailboxes, renders just /path.
|
||||||
:: for sponsor's mailboxes, renders ^/path.
|
:: for sponsor's mailboxes, renders ^/path.
|
||||||
::
|
::
|
||||||
::NOTE but, given current implementation, all will be local
|
|
||||||
::
|
|
||||||
++ phat
|
++ phat
|
||||||
^- tape
|
^- tape
|
||||||
|
%+ weld
|
||||||
|
?:(in-group.one "" "~/")
|
||||||
%+ weld
|
%+ weld
|
||||||
?: =(our-self ship.one) ~
|
?: =(our-self ship.one) ~
|
||||||
?: =((sein:title our.bowl now.bowl our-self) ship.one) "^"
|
?: =((sein:title our.bowl now.bowl our-self) ship.one) "^"
|
||||||
@ -1396,4 +1491,16 @@
|
|||||||
[(sub wid u.ace) &]
|
[(sub wid u.ace) &]
|
||||||
:- (tufa (scag end `(list @)`txt))
|
:- (tufa (scag end `(list @)`txt))
|
||||||
$(txt (slag ?:(nex +(end) end) `tape`txt))
|
$(txt (slag ?:(nex +(end) end) `tape`txt))
|
||||||
|
::
|
||||||
|
::NOTE anything that uses this breaks moons support, because moons don't sync
|
||||||
|
:: full app state rn
|
||||||
|
++ scry-for
|
||||||
|
|* [=mold app=term =path]
|
||||||
|
.^ mold
|
||||||
|
%gx
|
||||||
|
(scot %p our.bowl)
|
||||||
|
app
|
||||||
|
(scot %da now.bowl)
|
||||||
|
(snoc `^path`path %noun)
|
||||||
|
==
|
||||||
--
|
--
|
||||||
|
@ -2,18 +2,26 @@
|
|||||||
:: mirror chat data from foreign to local based on read permissions
|
:: mirror chat data from foreign to local based on read permissions
|
||||||
:: allow sending chat messages to foreign paths based on write perms
|
:: allow sending chat messages to foreign paths based on write perms
|
||||||
::
|
::
|
||||||
/- *permission-store, *chat-hook, *invite-store
|
/- *permission-store, *chat-hook, *invite-store, *metadata-store,
|
||||||
/+ *chat-json, default-agent, verb, dbug
|
*permission-hook, *group-store, *permission-group-hook ::TMP for upgrade
|
||||||
|
/+ *chat-json, *chat-eval, default-agent, verb, dbug
|
||||||
|
~% %chat-hook-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
::
|
::
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% state-zero
|
$% state-0
|
||||||
|
state-1
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ state-zero
|
+$ state-1
|
||||||
$: %0
|
$: %1
|
||||||
synced=(map path ship)
|
loaded-cards=(list card)
|
||||||
|
state-base
|
||||||
|
==
|
||||||
|
+$ state-0 [%0 state-base]
|
||||||
|
+$ state-base
|
||||||
|
$: =synced
|
||||||
invite-created=_|
|
invite-created=_|
|
||||||
allow-history=(map path ?)
|
allow-history=(map path ?)
|
||||||
==
|
==
|
||||||
@ -29,13 +37,14 @@
|
|||||||
$% [%chat-update chat-update]
|
$% [%chat-update chat-update]
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
=| state-zero
|
=| state-1
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
%+ verb |
|
%+ verb |
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|
~% %chat-hook-agent-core ..poke-json ~
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
chat-core +>
|
chat-core +>
|
||||||
@ -51,29 +60,199 @@
|
|||||||
==
|
==
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old=vase
|
|= old-vase=vase
|
||||||
`this(state !<(state-zero old))
|
^- (quip card _this)
|
||||||
|
|^
|
||||||
|
=/ old !<(versioned-state old-vase)
|
||||||
|
?: ?=(%1 -.old)
|
||||||
|
:_ this(state old)
|
||||||
|
%+ murn ~(tap by wex.bol)
|
||||||
|
|= [[=wire =ship =term] *]
|
||||||
|
^- (unit card)
|
||||||
|
?. &(?=([%mailbox *] wire) =(our.bol ship) =(%chat-store term))
|
||||||
|
~
|
||||||
|
`[%pass wire %agent [our.bol %chat-store] %leave ~]
|
||||||
|
:: path structure ugprade logic
|
||||||
|
::
|
||||||
|
=/ keys=(set path) (scry:cc (set path) %chat-store /keys)
|
||||||
|
=/ upgraded-state
|
||||||
|
%* . *state-1
|
||||||
|
synced synced
|
||||||
|
invite-created invite-created
|
||||||
|
allow-history allow-history
|
||||||
|
loaded-cards
|
||||||
|
%- zing
|
||||||
|
^- (list (list card))
|
||||||
|
%+ turn ~(tap in keys) generate-cards
|
||||||
|
==
|
||||||
|
[loaded-cards.upgraded-state this(state upgraded-state)]
|
||||||
|
::
|
||||||
|
++ generate-cards
|
||||||
|
|= old-chat=path
|
||||||
|
^- (list card)
|
||||||
|
=/ host=ship (slav %p (snag 0 old-chat))
|
||||||
|
=/ new-chat [%'~' old-chat]
|
||||||
|
=/ newp=permission (unify-permissions old-chat)
|
||||||
|
=/ old-group=path [%chat old-chat]
|
||||||
|
%- zing
|
||||||
|
:~ :~ (delete-group host (snoc old-group %read))
|
||||||
|
(delete-group host (snoc old-group %write))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
(create-group new-chat who.newp)
|
||||||
|
(hookup-group new-chat kind.newp)
|
||||||
|
[(record-group new-chat new-chat)]~
|
||||||
|
(recreate-chat host old-chat new-chat)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ recreate-chat
|
||||||
|
|= [host=ship chat=path new-chat=path]
|
||||||
|
^- (list card)
|
||||||
|
=/ old-mailbox=mailbox
|
||||||
|
(need (scry:cc (unit mailbox) %chat-store [%mailbox chat]))
|
||||||
|
=* enves envelopes.old-mailbox
|
||||||
|
:~ (chat-poke:cc [%delete new-chat])
|
||||||
|
(chat-poke:cc [%delete chat])
|
||||||
|
(chat-poke:cc [%create new-chat])
|
||||||
|
(chat-poke:cc [%messages new-chat enves])
|
||||||
|
(chat-poke:cc [%read new-chat])
|
||||||
|
%^ make-poke %chat-hook %chat-hook-action
|
||||||
|
!> ^- chat-hook-action
|
||||||
|
?: =(our.bol host) [%add-owned new-chat %.y]
|
||||||
|
[%add-synced host new-chat %.y]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ unify-permissions
|
||||||
|
|= chat=path
|
||||||
|
^- permission
|
||||||
|
=/ read=(unit permission) (get-permission chat %read)
|
||||||
|
=/ write=(unit permission) (get-permission chat %write)
|
||||||
|
?. &(?=(^ read) ?=(^ write))
|
||||||
|
~& [%missing-permission chat read=?=(~ read) write=?=(~ write)]
|
||||||
|
[%white [(slav %p (snag 0 chat)) ~ ~]]
|
||||||
|
?+ [kind.u.read kind.u.write] !!
|
||||||
|
:: village: exclusive to writers
|
||||||
|
::
|
||||||
|
[%white %white] [%white who.u.write]
|
||||||
|
::
|
||||||
|
:: channel: merge blacklists
|
||||||
|
::
|
||||||
|
[%black %black] [%black (~(uni in who.u.read) who.u.write)]
|
||||||
|
::
|
||||||
|
:: journal: exclusive to writers
|
||||||
|
::
|
||||||
|
[%black %white] [%white who.u.write]
|
||||||
|
::
|
||||||
|
:: mailbox: exclusive to readers
|
||||||
|
::
|
||||||
|
[%white %black] [%white who.u.read]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ get-permission
|
||||||
|
|= [chat=path what=?(%read %write)]
|
||||||
|
%^ scry:cc (unit permission)
|
||||||
|
%permission-store
|
||||||
|
[%permission %chat (snoc chat what)]
|
||||||
|
::
|
||||||
|
++ make-poke
|
||||||
|
|= [app=term =mark =vase]
|
||||||
|
^- card
|
||||||
|
[%pass /on-load/[app]/[mark] %agent [our.bol app] %poke mark vase]
|
||||||
|
::
|
||||||
|
++ delete-group
|
||||||
|
|= [host=ship group=path]
|
||||||
|
^- card
|
||||||
|
:: if we host the group, delete it directly
|
||||||
|
::
|
||||||
|
?: =(our.bol host)
|
||||||
|
%^ make-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action
|
||||||
|
[%unbundle group]
|
||||||
|
:: else, just delete the sync in the hook
|
||||||
|
::
|
||||||
|
%^ make-poke %permission-hook
|
||||||
|
%permission-hook-action
|
||||||
|
!> ^- permission-hook-action
|
||||||
|
[%remove group]
|
||||||
|
::
|
||||||
|
++ create-group
|
||||||
|
|= [group=path who=(set ship)]
|
||||||
|
^- (list card)
|
||||||
|
:~ %^ make-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action
|
||||||
|
[%bundle group]
|
||||||
|
::
|
||||||
|
%^ make-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action
|
||||||
|
[%add who group]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ hookup-group
|
||||||
|
|= [group=path =kind]
|
||||||
|
^- (list card)
|
||||||
|
:* %^ make-poke %permission-group-hook
|
||||||
|
%permission-group-hook-action
|
||||||
|
!> ^- permission-group-hook-action
|
||||||
|
[%associate group [group^kind ~ ~]]
|
||||||
|
::
|
||||||
|
=/ =ship (slav %p (snag 1 group))
|
||||||
|
?. =(our.bol ship) ~
|
||||||
|
:_ ~
|
||||||
|
%^ make-poke %permission-hook
|
||||||
|
%permission-hook-action
|
||||||
|
!> ^- permission-hook-action
|
||||||
|
[%add-owned group group]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ record-group
|
||||||
|
|= [group=path chat=path]
|
||||||
|
^- card
|
||||||
|
=/ =metadata
|
||||||
|
~| [%weird-chat-path chat]
|
||||||
|
%* . *metadata
|
||||||
|
title (snag 2 chat)
|
||||||
|
date-created now.bol
|
||||||
|
creator (slav %p (snag 1 chat))
|
||||||
|
==
|
||||||
|
%^ make-poke %metadata-store
|
||||||
|
%metadata-action
|
||||||
|
!> ^- metadata-action
|
||||||
|
[%add group [%chat chat] metadata]
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|
~/ %chat-hook-poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
=^ cards state
|
=^ cards state
|
||||||
?+ mark (on-poke:def mark vase)
|
?+ mark (on-poke:def mark vase)
|
||||||
%json (poke-json:cc !<(json vase))
|
%json (poke-json:cc !<(json vase))
|
||||||
%chat-action (poke-chat-action:cc !<(chat-action vase))
|
%chat-action (poke-chat-action:cc !<(chat-action vase))
|
||||||
%chat-hook-action (poke-chat-hook-action:cc !<(chat-hook-action vase))
|
%noun
|
||||||
|
?: =(%store-load q.vase)
|
||||||
|
[loaded-cards.state state(loaded-cards ~)]
|
||||||
|
[~ state]
|
||||||
|
::
|
||||||
|
%chat-hook-action
|
||||||
|
(poke-chat-hook-action:cc !<(chat-hook-action vase))
|
||||||
==
|
==
|
||||||
[cards this]
|
[cards this]
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
|
~/ %chat-hook-watch
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?+ path (on-watch:def path)
|
?+ path (on-watch:def path)
|
||||||
[%backlog *] [(watch-backlog:cc t.path) this]
|
[%backlog *] [(watch-backlog:cc t.path) this]
|
||||||
[%mailbox *] [(watch-mailbox:cc t.path) this]
|
[%mailbox *] [(watch-mailbox:cc t.path) this]
|
||||||
|
[%synced *] [(watch-synced:cc t.path) this]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-agent
|
++ on-agent
|
||||||
|
~/ %chat-hook-agent
|
||||||
|= [=wire =sign:agent:gall]
|
|= [=wire =sign:agent:gall]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?+ -.sign (on-agent:def wire sign)
|
?+ -.sign (on-agent:def wire sign)
|
||||||
@ -113,6 +292,7 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
::
|
::
|
||||||
|
~% %chat-hook-library ..card ~
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
::
|
::
|
||||||
++ poke-json
|
++ poke-json
|
||||||
@ -129,18 +309,19 @@
|
|||||||
?: (team:title our.bol src.bol)
|
?: (team:title our.bol src.bol)
|
||||||
?. (~(has by synced) path.act)
|
?. (~(has by synced) path.act)
|
||||||
~
|
~
|
||||||
|
=* letter letter.envelope.act
|
||||||
|
=? letter &(?=(%code -.letter) ?=(~ output.letter))
|
||||||
|
=/ =hoon (ream expression.letter)
|
||||||
|
letter(output (eval bol hoon))
|
||||||
=/ ship (~(got by synced) path.act)
|
=/ ship (~(got by synced) path.act)
|
||||||
=/ appl ?:(=(ship our.bol) %chat-store %chat-hook)
|
=/ appl ?:(=(ship our.bol) %chat-store %chat-hook)
|
||||||
[%pass / %agent [ship appl] %poke %chat-action !>(act)]~
|
[%pass / %agent [ship appl] %poke %chat-action !>(act)]~
|
||||||
:: foreign
|
:: foreign
|
||||||
=/ ship (~(get by synced) path.act)
|
=/ ship (~(get by synced) path.act)
|
||||||
?~ ship
|
?~ ship ~
|
||||||
~
|
?. =(u.ship our.bol) ~
|
||||||
?. =(u.ship our.bol)
|
:: check if write is permitted
|
||||||
~
|
?. (is-permitted src.bol path.act) ~
|
||||||
:: scry permissions to check if write is permitted
|
|
||||||
?. (permitted-scry [(scot %p src.bol) %chat (weld path.act /write)])
|
|
||||||
~
|
|
||||||
=: author.envelope.act src.bol
|
=: author.envelope.act src.bol
|
||||||
when.envelope.act now.bol
|
when.envelope.act now.bol
|
||||||
==
|
==
|
||||||
@ -153,158 +334,154 @@
|
|||||||
%add-owned
|
%add-owned
|
||||||
?> (team:title our.bol src.bol)
|
?> (team:title our.bol src.bol)
|
||||||
=/ chat-path [%mailbox path.act]
|
=/ chat-path [%mailbox path.act]
|
||||||
?: (~(has by synced) path.act)
|
=/ chat-wire [%store path.act]
|
||||||
[~ state]
|
?: (~(has by synced) path.act) [~ state]
|
||||||
=: synced (~(put by synced) path.act our.bol)
|
=: synced (~(put by synced) path.act our.bol)
|
||||||
allow-history (~(put by allow-history) path.act allow-history.act)
|
allow-history (~(put by allow-history) path.act allow-history.act)
|
||||||
==
|
==
|
||||||
:_ state
|
:_ state
|
||||||
%+ weld
|
:~ [%pass chat-wire %agent [our.bol %chat-store] %watch chat-path]
|
||||||
[%pass chat-path %agent [our.bol %chat-store] %watch chat-path]~
|
[%give %fact [/synced]~ %chat-hook-update !>([%initial synced])]
|
||||||
(create-permission [%chat path.act] security.act)
|
==
|
||||||
::
|
::
|
||||||
%add-synced
|
%add-synced
|
||||||
?> (team:title our.bol src.bol)
|
?> (team:title our.bol src.bol)
|
||||||
?: (~(has by synced) [(scot %p ship.act) path.act])
|
?: (~(has by synced) path.act) [~ state]
|
||||||
[~ state]
|
=. synced (~(put by synced) path.act ship.act)
|
||||||
=. synced (~(put by synced) [(scot %p ship.act) path.act] ship.act)
|
|
||||||
?. ask-history.act
|
?. ask-history.act
|
||||||
=/ chat-path [%mailbox (scot %p ship.act) path.act]
|
=/ chat-path [%mailbox path.act]
|
||||||
:_ state
|
:_ state
|
||||||
[%pass chat-path %agent [ship.act %chat-hook] %watch chat-path]~
|
[%pass chat-path %agent [ship.act %chat-hook] %watch chat-path]~
|
||||||
:: TODO: only ask for backlog from previous point
|
=/ mailbox=(unit mailbox) (chat-scry path.act)
|
||||||
=/ chat-history [%backlog (scot %p ship.act) (weld path.act /0)]
|
=/ chat-history=path
|
||||||
|
:- %backlog
|
||||||
|
%+ weld path.act
|
||||||
|
?~(mailbox /0 /(scot %ud (lent envelopes.u.mailbox)))
|
||||||
:_ state
|
:_ state
|
||||||
[%pass chat-history %agent [ship.act %chat-hook] %watch chat-history]~
|
:~ [%pass chat-history %agent [ship.act %chat-hook] %watch chat-history]
|
||||||
|
[%give %fact [/synced]~ %chat-hook-update !>([%initial synced])]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
%remove
|
%remove
|
||||||
=/ ship (~(get by synced) path.act)
|
=/ ship=(unit ship)
|
||||||
|
=/ ship (~(get by synced) path.act)
|
||||||
|
?^ ship ship
|
||||||
|
=? path.act ?=([%'~' *] path.act) t.path.act
|
||||||
|
?~ path.act ~
|
||||||
|
(slaw %p i.path.act)
|
||||||
?~ ship
|
?~ ship
|
||||||
|
~& [dap.bol %unknown-host-cannot-leave path.act]
|
||||||
[~ state]
|
[~ state]
|
||||||
?: &(=(u.ship our.bol) (team:title our.bol src.bol))
|
?: &(!=(u.ship src.bol) ?!((team:title our.bol src.bol)))
|
||||||
:: delete one of our.bol own paths
|
|
||||||
:_ state(synced (~(del by synced) path.act))
|
|
||||||
%- zing
|
|
||||||
:~ (pull-wire [%backlog (weld path.act /0)])
|
|
||||||
(pull-wire [%mailbox path.act])
|
|
||||||
(delete-permission [%chat path.act])
|
|
||||||
[%give %kick [%mailbox path.act]~ ~]~
|
|
||||||
==
|
|
||||||
?. |(=(u.ship src.bol) (team:title our.bol src.bol))
|
|
||||||
:: if neither ship = source or source = us, do nothing
|
|
||||||
[~ state]
|
[~ state]
|
||||||
:: delete a foreign ship's path
|
=. synced (~(del by synced) path.act)
|
||||||
:- (pull-wire [%mailbox path.act])
|
:_ state
|
||||||
state(synced (~(del by synced) path.act))
|
:* [%give %kick ~[[%mailbox path.act]] ~]
|
||||||
|
[%give %fact [/synced]~ %chat-hook-update !>([%initial synced])]
|
||||||
|
(pull-wire u.ship [%mailbox path.act])
|
||||||
|
(pull-backlog-subscriptions u.ship path.act)
|
||||||
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
++ watch-synced
|
||||||
|
|= pax=path
|
||||||
|
^- (list card)
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
[%give %fact ~ %chat-hook-update !>([%initial synced])]~
|
||||||
|
::
|
||||||
++ watch-mailbox
|
++ watch-mailbox
|
||||||
|= pax=path
|
|= pax=path
|
||||||
^- (list card)
|
^- (list card)
|
||||||
?> ?=(^ pax)
|
?> ?=(^ pax)
|
||||||
?> (~(has by synced) pax)
|
?> (~(has by synced) pax)
|
||||||
:: scry permissions to check if read is permitted
|
:: check if read is permitted
|
||||||
?> (permitted-scry [(scot %p src.bol) %chat (weld pax /read)])
|
?> (is-permitted src.bol pax)
|
||||||
=/ box (chat-scry pax)
|
=/ box (chat-scry pax)
|
||||||
?~ box !!
|
?~ box !!
|
||||||
[%give %fact ~ %chat-update !>([%create (slav %p i.pax) pax])]~
|
[%give %fact ~ %chat-update !>([%create pax])]~
|
||||||
::
|
::
|
||||||
++ watch-backlog
|
++ watch-backlog
|
||||||
|= pax=path
|
|= pax=path
|
||||||
^- (list card)
|
^- (list card)
|
||||||
?> ?=(^ pax)
|
?> ?=(^ pax)
|
||||||
=/ last (dec (lent pax))
|
=/ last (dec (lent pax))
|
||||||
=/ backlog-start=(unit @ud)
|
=/ backlog-latest=(unit @ud) (rush (snag last `(list @ta)`pax) dem:ag)
|
||||||
%+ rush
|
|
||||||
(snag last `(list @ta)`pax)
|
|
||||||
dem:ag
|
|
||||||
=/ pas `path`(oust [last 1] `(list @ta)`pax)
|
=/ pas `path`(oust [last 1] `(list @ta)`pax)
|
||||||
?> ?=([* ^] pas)
|
?> ?=([* ^] pas)
|
||||||
?> (~(has by synced) pas)
|
?> (~(has by synced) pas)
|
||||||
:: scry permissions to check if read is permitted
|
?> (is-permitted src.bol pas)
|
||||||
?> (permitted-scry [(scot %p src.bol) %chat (weld pas /read)])
|
=/ envs envelopes:(need (chat-scry pas))
|
||||||
=/ box (chat-scry pas)
|
=/ length (lent envs)
|
||||||
?~ box !!
|
=/ latest
|
||||||
:- [%give %fact ~ %chat-update !>([%create (slav %p i.pas) pas])]
|
?~ backlog-latest length
|
||||||
|
?: (gth u.backlog-latest length) length
|
||||||
|
(sub length u.backlog-latest)
|
||||||
|
=. envs (scag latest envs)
|
||||||
|
=/ =vase !>([%messages pas 0 latest envs])
|
||||||
%- zing
|
%- zing
|
||||||
:~
|
:~ [%give %fact ~ %chat-update !>([%create pas])]~
|
||||||
?: ?&(?=(^ backlog-start) (~(got by allow-history) pas))
|
?. ?&(?=(^ backlog-latest) (~(has by allow-history) pas)) ~
|
||||||
(paginate-messages pas u.box u.backlog-start)
|
[%give %fact ~ %chat-update vase]~
|
||||||
~
|
[%give %kick [%backlog pax]~ `src.bol]~
|
||||||
[%give %kick [%backlog pax]~ `src.bol]~
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ paginate-messages
|
|
||||||
|= [=path =mailbox start=@ud]
|
|
||||||
^- (list card)
|
|
||||||
=/ cards=(list card) ~
|
|
||||||
=/ end (lent envelopes.mailbox)
|
|
||||||
?: |((gte start end) =(end 0))
|
|
||||||
cards
|
|
||||||
=. envelopes.mailbox (slag start `(list envelope)`envelopes.mailbox)
|
|
||||||
|- ^- (list card)
|
|
||||||
?~ envelopes.mailbox
|
|
||||||
cards
|
|
||||||
?: (lte end 5.000)
|
|
||||||
=. cards
|
|
||||||
%+ snoc cards
|
|
||||||
%- messages-fact
|
|
||||||
[path start (lent envelopes.mailbox) envelopes.mailbox]
|
|
||||||
$(envelopes.mailbox ~)
|
|
||||||
=. cards
|
|
||||||
%+ snoc cards
|
|
||||||
%- messages-fact
|
|
||||||
:^ path start
|
|
||||||
(add start 5.000)
|
|
||||||
(scag 5.000 `(list envelope)`envelopes.mailbox)
|
|
||||||
=: start (add start 5.000)
|
|
||||||
end (sub end 5.000)
|
|
||||||
==
|
|
||||||
$(envelopes.mailbox (slag 5.000 `(list envelope)`envelopes.mailbox))
|
|
||||||
::
|
|
||||||
++ fact-invite-update
|
++ fact-invite-update
|
||||||
|= [wir=wire fact=invite-update]
|
|= [wir=wire fact=invite-update]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?+ -.fact
|
:_ state
|
||||||
[~ state]
|
?+ -.fact ~
|
||||||
::
|
|
||||||
%accepted
|
%accepted
|
||||||
=/ ask-history
|
=/ ask-history ?~((chat-scry path.invite.fact) %.y %.n)
|
||||||
?~ (chat-scry [(scot %p ship.invite.fact) path.invite.fact])
|
=* shp ship.invite.fact
|
||||||
%.y
|
=* app-path path.invite.fact
|
||||||
%.n
|
~[(chat-view-poke [%join shp app-path ask-history])]
|
||||||
:_ state
|
==
|
||||||
[(chat-view-poke [%join ship.invite.fact path.invite.fact ask-history])]~
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
++ fact-permission-update
|
++ fact-permission-update
|
||||||
|= [wir=wire fact=permission-update]
|
|= [wir=wire fact=permission-update]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
|
|^
|
||||||
:_ state
|
:_ state
|
||||||
?- -.fact
|
?+ -.fact ~
|
||||||
%create ~
|
|
||||||
%delete ~
|
|
||||||
%add (handle-permissions [%add path.fact who.fact])
|
%add (handle-permissions [%add path.fact who.fact])
|
||||||
%remove (handle-permissions [%remove path.fact who.fact])
|
%remove (handle-permissions [%remove path.fact who.fact])
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ handle-permissions
|
++ handle-permissions
|
||||||
|= [kind=?(%add %remove) pax=path who=(set ship)]
|
|= [kind=?(%add %remove) pax=path who=(set ship)]
|
||||||
^- (list card)
|
^- (list card)
|
||||||
?> ?=([* *] pax)
|
%- zing
|
||||||
?. =(%chat i.pax) ~
|
%+ turn
|
||||||
:: check path to see if this is a %read permission
|
(chats-of-group pax)
|
||||||
?. =(%read (snag (dec (lent pax)) `(list @t)`pax))
|
|= chat=path
|
||||||
~
|
^- (list card)
|
||||||
%- zing
|
=/ owner (~(get by synced) chat)
|
||||||
%+ turn ~(tap in who)
|
?~ owner ~
|
||||||
|= =ship
|
?. =(u.owner our.bol) ~
|
||||||
?: (permitted-scry [(scot %p ship) pax])
|
%- zing
|
||||||
~
|
%+ turn ~(tap in who)
|
||||||
:: if ship is not permitted, kick their subscription
|
|= =ship
|
||||||
=/ mail-path
|
?: (is-permitted ship chat)
|
||||||
(oust [(dec (lent t.pax)) (lent t.pax)] `(list @t)`t.pax)
|
?: ?|(=(kind %remove) =(ship our.bol) (is-managed pax)) ~
|
||||||
[%give %kick [%mailbox mail-path]~ `ship]~
|
:: if ship has just been added to the permitted group,
|
||||||
|
:: send them an invite
|
||||||
|
~[(send-invite chat ship)]
|
||||||
|
:: if ship is not permitted, kick their subscription
|
||||||
|
[%give %kick [%mailbox chat]~ `ship]~
|
||||||
|
::
|
||||||
|
++ send-invite
|
||||||
|
|= [=path =ship]
|
||||||
|
^- card
|
||||||
|
=/ =invite [our.bol %chat-hook path ship '']
|
||||||
|
=/ act=invite-action [%invite /chat (shaf %msg-uid eny.bol) invite]
|
||||||
|
[%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)]
|
||||||
|
::
|
||||||
|
++ is-managed
|
||||||
|
|= =path
|
||||||
|
^- ?
|
||||||
|
?> ?=(^ path)
|
||||||
|
!=(i.path '~')
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ fact-chat-update
|
++ fact-chat-update
|
||||||
|= [wir=wire fact=chat-update]
|
|= [wir=wire fact=chat-update]
|
||||||
@ -316,16 +493,14 @@
|
|||||||
++ handle-local
|
++ handle-local
|
||||||
|= fact=chat-update
|
|= fact=chat-update
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?- -.fact
|
?+ -.fact [~ state]
|
||||||
%keys [~ state]
|
|
||||||
%read [~ state]
|
|
||||||
%config [~ state]
|
|
||||||
%create [~ state]
|
|
||||||
%delete
|
%delete
|
||||||
?. (~(has by synced) path.fact)
|
?. (~(has by synced) path.fact) [~ state]
|
||||||
[~ state]
|
=. synced (~(del by synced) path.fact)
|
||||||
:_ state(synced (~(del by synced) path.fact))
|
:_ state
|
||||||
[%pass [%mailbox path.fact] %agent [our.bol %chat-store] %leave ~]~
|
:~ [%pass [%mailbox path.fact] %agent [our.bol %chat-store] %leave ~]
|
||||||
|
[%give %fact [/synced]~ %chat-hook-update !>([%initial synced])]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
%message
|
%message
|
||||||
:_ state
|
:_ state
|
||||||
@ -339,28 +514,26 @@
|
|||||||
++ handle-foreign
|
++ handle-foreign
|
||||||
|= fact=chat-update
|
|= fact=chat-update
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?- -.fact
|
?+ -.fact [~ state]
|
||||||
%keys [~ state]
|
|
||||||
%read [~ state]
|
|
||||||
%config [~ state]
|
|
||||||
%create
|
%create
|
||||||
:_ state
|
:_ state
|
||||||
?> ?=([* ^] path.fact)
|
?> ?=([* ^] path.fact)
|
||||||
=/ shp (~(get by synced) path.fact)
|
=/ shp (~(get by synced) path.fact)
|
||||||
?~ shp ~
|
?~ shp ~
|
||||||
?. =(src.bol u.shp) ~
|
?. =(src.bol u.shp) ~
|
||||||
[(chat-poke [%create ship.fact t.path.fact])]~
|
[(chat-poke [%create path.fact])]~
|
||||||
::
|
::
|
||||||
%delete
|
%delete
|
||||||
?> ?=([* ^] path.fact)
|
?> ?=([* ^] path.fact)
|
||||||
=/ shp (~(get by synced) path.fact)
|
=/ shp (~(get by synced) path.fact)
|
||||||
?~ shp
|
?~ shp [~ state]
|
||||||
[~ state]
|
?. =(u.shp src.bol) [~ state]
|
||||||
?. =(u.shp src.bol)
|
=. synced (~(del by synced) path.fact)
|
||||||
[~ state]
|
:_ state
|
||||||
:_ state(synced (~(del by synced) path.fact))
|
|
||||||
:- (chat-poke [%delete path.fact])
|
:- (chat-poke [%delete path.fact])
|
||||||
[%pass [%mailbox path.fact] %agent [src.bol %chat-hook] %leave ~]~
|
:~ [%pass [%mailbox path.fact] %agent [src.bol %chat-hook] %leave ~]
|
||||||
|
[%give %fact [/synced]~ %chat-hook-update !>([%initial synced])]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
%message
|
%message
|
||||||
:_ state
|
:_ state
|
||||||
@ -386,43 +559,56 @@
|
|||||||
:_ state
|
:_ state
|
||||||
[%pass /permissions %agent [our.bol %permission-store] %watch /updates]~
|
[%pass /permissions %agent [our.bol %permission-store] %watch /updates]~
|
||||||
::
|
::
|
||||||
?: ?=([%mailbox @ *] wir)
|
?+ wir !!
|
||||||
|
[%store @ *]
|
||||||
|
~& store-kick+wir
|
||||||
|
?. (~(has by synced) t.wir) [~ state]
|
||||||
|
~& %chat-store-resubscribe
|
||||||
|
=/ mailbox=(unit mailbox) (chat-scry t.wir)
|
||||||
|
:_ state
|
||||||
|
[%pass wir %agent [our.bol %chat-store] %watch [%mailbox t.wir]]~
|
||||||
|
::
|
||||||
|
[%mailbox @ *]
|
||||||
~& mailbox-kick+wir
|
~& mailbox-kick+wir
|
||||||
?. (~(has by synced) t.wir)
|
?. (~(has by synced) t.wir) [~ state]
|
||||||
:: no-op
|
|
||||||
[~ state]
|
|
||||||
~& %chat-hook-resubscribe
|
~& %chat-hook-resubscribe
|
||||||
=/ =ship (~(got by synced) t.wir)
|
=/ =ship (~(got by synced) t.wir)
|
||||||
=/ mailbox=(unit mailbox) (chat-scry t.wir)
|
=/ mailbox=(unit mailbox) (chat-scry t.wir)
|
||||||
=/ chat-history
|
=/ chat-history
|
||||||
%+ welp backlog+t.wir
|
%+ welp backlog+t.wir
|
||||||
?~ mailbox
|
?~(mailbox /0 /(scot %ud (lent envelopes.u.mailbox)))
|
||||||
/0
|
|
||||||
/(scot %ud (lent envelopes.u.mailbox))
|
|
||||||
:_ state
|
:_ state
|
||||||
[%pass chat-history %agent [ship %chat-hook] %watch chat-history]~
|
[%pass chat-history %agent [ship %chat-hook] %watch chat-history]~
|
||||||
::
|
::
|
||||||
?: ?=([%backlog @ *] wir)
|
[%backlog @ @ *]
|
||||||
=/ pax `path`(oust [(dec (lent t.wir)) 1] `(list @ta)`t.wir)
|
=/ chat=path (oust [(dec (lent t.wir)) 1] `(list @ta)`t.wir)
|
||||||
?. (~(has by synced) pax) [~ state]
|
?. (~(has by synced) chat) [~ state]
|
||||||
=/ mailbox=(unit mailbox) (chat-scry pax)
|
=/ =ship
|
||||||
=. pax ?~(mailbox wir [%mailbox pax])
|
?: =('~' i.t.wir)
|
||||||
|
(slav %p i.t.t.wir)
|
||||||
|
(slav %p i.t.wir)
|
||||||
|
=/ =path ?~((chat-scry chat) wir [%mailbox chat])
|
||||||
:_ state
|
:_ state
|
||||||
[%pass pax %agent [(slav %p i.t.wir) %chat-hook] %watch pax]~
|
[%pass path %agent [ship %chat-hook] %watch path]~
|
||||||
!!
|
==
|
||||||
::
|
::
|
||||||
++ watch-ack
|
++ watch-ack
|
||||||
|= [wir=wire saw=(unit tang)]
|
|= [wir=wire saw=(unit tang)]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?~ saw
|
?~ saw [~ state]
|
||||||
[~ state]
|
?+ wir [~ state]
|
||||||
?> ?=(^ wir)
|
[%store @ *]
|
||||||
:_ state(synced (~(del by synced) t.wir))
|
(poke-chat-hook-action %remove t.wir)
|
||||||
%. ~
|
::
|
||||||
%- slog
|
[%backlog @ @ @ *]
|
||||||
:* leaf+"chat-hook failed subscribe on {(spud t.wir)}"
|
=/ chat=path (oust [(dec (lent t.wir)) 1] `(list @ta)`t.wir)
|
||||||
leaf+"stack trace:"
|
:_ state
|
||||||
u.saw
|
%. ~[(chat-view-poke %delete chat)]
|
||||||
|
%- slog
|
||||||
|
:* leaf+"chat-hook failed subscribe on {(spud chat)}"
|
||||||
|
leaf+"stack trace:"
|
||||||
|
u.saw
|
||||||
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ chat-poke
|
++ chat-poke
|
||||||
@ -435,57 +621,11 @@
|
|||||||
^- card
|
^- card
|
||||||
[%pass / %agent [our.bol %chat-view] %poke %chat-view-action !>(act)]
|
[%pass / %agent [our.bol %chat-view] %poke %chat-view-action !>(act)]
|
||||||
::
|
::
|
||||||
++ permission-poke
|
|
||||||
|= act=permission-action
|
|
||||||
^- card
|
|
||||||
[%pass / %agent [our.bol %permission-store] %poke %permission-action !>(act)]
|
|
||||||
::
|
|
||||||
++ invite-poke
|
++ invite-poke
|
||||||
|= act=invite-action
|
|= act=invite-action
|
||||||
^- card
|
^- card
|
||||||
[%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)]
|
[%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)]
|
||||||
::
|
::
|
||||||
++ messages-fact
|
|
||||||
|= [=path start=@ud end=@ud envelopes=(list envelope)]
|
|
||||||
^- card
|
|
||||||
[%give %fact ~ %chat-update !>([%messages path start end envelopes])]
|
|
||||||
::
|
|
||||||
++ create-permission
|
|
||||||
|= [pax=path sec=rw-security]
|
|
||||||
^- (list card)
|
|
||||||
=/ read-perm (weld pax /read)
|
|
||||||
=/ write-perm (weld pax /write)
|
|
||||||
?- sec
|
|
||||||
%channel
|
|
||||||
:~ (permission-poke (sec-to-perm read-perm %black))
|
|
||||||
(permission-poke (sec-to-perm write-perm %black))
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%village
|
|
||||||
:~ (permission-poke (sec-to-perm read-perm %white))
|
|
||||||
(permission-poke (sec-to-perm write-perm %white))
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%journal
|
|
||||||
:~ (permission-poke (sec-to-perm read-perm %black))
|
|
||||||
(permission-poke (sec-to-perm write-perm %white))
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%mailbox
|
|
||||||
:~ (permission-poke (sec-to-perm read-perm %white))
|
|
||||||
(permission-poke (sec-to-perm write-perm %black))
|
|
||||||
==
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ delete-permission
|
|
||||||
|= pax=path
|
|
||||||
^- (list card)
|
|
||||||
=/ read-perm (weld pax /read)
|
|
||||||
=/ write-perm (weld pax /write)
|
|
||||||
:~ (permission-poke [%delete read-perm])
|
|
||||||
(permission-poke [%delete write-perm])
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ sec-to-perm
|
++ sec-to-perm
|
||||||
|= [pax=path =kind]
|
|= [pax=path =kind]
|
||||||
^- permission-action
|
^- permission-action
|
||||||
@ -494,27 +634,104 @@
|
|||||||
++ chat-scry
|
++ chat-scry
|
||||||
|= pax=path
|
|= pax=path
|
||||||
^- (unit mailbox)
|
^- (unit mailbox)
|
||||||
=. pax ;:(weld /=chat-store/(scot %da now.bol)/mailbox pax /noun)
|
%^ scry (unit mailbox)
|
||||||
.^((unit mailbox) %gx pax)
|
%chat-store
|
||||||
|
[%mailbox pax]
|
||||||
::
|
::
|
||||||
++ invite-scry
|
++ invite-scry
|
||||||
|= uid=serial
|
|= uid=serial
|
||||||
^- (unit invite)
|
^- (unit invite)
|
||||||
=/ pax /=invite-store/(scot %da now.bol)/invite/chat/(scot %uv uid)/noun
|
%^ scry (unit invite)
|
||||||
.^((unit invite) %gx pax)
|
%invite-store
|
||||||
|
/invite/chat/(scot %uv uid)
|
||||||
::
|
::
|
||||||
++ permitted-scry
|
++ chats-of-group
|
||||||
|= pax=path
|
|= =group-path
|
||||||
|
^- (list path)
|
||||||
|
:: if metadata-store isn't running yet, we're still in the upgrade ota phase.
|
||||||
|
:: we can't get chats from the metadata-store, but can make assumptions
|
||||||
|
:: about group path shape, and the chat that would match it.
|
||||||
|
::TODO remove me at some point.
|
||||||
|
::
|
||||||
|
?. .^(? %gu (scot %p our.bol) %metadata-store (scot %da now.bol) ~) ~
|
||||||
|
%+ murn
|
||||||
|
^- (list resource)
|
||||||
|
=; resources
|
||||||
|
%~ tap in
|
||||||
|
%+ ~(gut by resources)
|
||||||
|
group-path
|
||||||
|
*(set resource)
|
||||||
|
.^ (jug path resource)
|
||||||
|
%gy
|
||||||
|
(scot %p our.bol)
|
||||||
|
%metadata-store
|
||||||
|
(scot %da now.bol)
|
||||||
|
/group-indices
|
||||||
|
==
|
||||||
|
|= resource
|
||||||
|
^- (unit path)
|
||||||
|
?. =(%chat app-name) ~
|
||||||
|
`app-path
|
||||||
|
::
|
||||||
|
++ groups-of-chat
|
||||||
|
|= chat=path
|
||||||
|
^- (list group-path)
|
||||||
|
:: if metadata-store isn't running yet, we're still in the upgrade ota phase.
|
||||||
|
:: we can't get groups from the metadata-store, but can make assumptions
|
||||||
|
:: about chat path shape, and the chat that would match it.
|
||||||
|
::TODO remove me at some point.
|
||||||
|
::
|
||||||
|
?. .^(? %gu (scot %p our.bol) %metadata-store (scot %da now.bol) ~) ~
|
||||||
|
=; resources
|
||||||
|
%~ tap in
|
||||||
|
%+ ~(gut by resources)
|
||||||
|
[%chat chat]
|
||||||
|
*(set group-path)
|
||||||
|
.^ (jug resource group-path)
|
||||||
|
%gy
|
||||||
|
(scot %p our.bol)
|
||||||
|
%metadata-store
|
||||||
|
(scot %da now.bol)
|
||||||
|
/resource-indices
|
||||||
|
==
|
||||||
|
::
|
||||||
|
::NOTE this assumes permission paths match group paths
|
||||||
|
++ is-permitted
|
||||||
|
|= [who=ship chat=path]
|
||||||
^- ?
|
^- ?
|
||||||
.^(? %gx ;:(weld /=permission-store/(scot %da now.bol)/permitted pax /noun))
|
%+ lien (groups-of-chat chat)
|
||||||
|
|= =group-path
|
||||||
|
%^ scry ?
|
||||||
|
%permission-store
|
||||||
|
[%permitted (scot %p who) group-path]
|
||||||
|
::
|
||||||
|
++ scry
|
||||||
|
|* [=mold app=term =path]
|
||||||
|
.^ mold
|
||||||
|
%gx
|
||||||
|
(scot %p our.bol)
|
||||||
|
app
|
||||||
|
(scot %da now.bol)
|
||||||
|
(snoc `^path`path %noun)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ pull-backlog-subscriptions
|
||||||
|
|= [target=ship chat=path]
|
||||||
|
^- (list card)
|
||||||
|
%+ murn ~(tap by wex.bol)
|
||||||
|
|= [[=wire =ship =term] [acked=? =path]]
|
||||||
|
^- (unit card)
|
||||||
|
?. ?& =(ship target)
|
||||||
|
?=([%backlog *] wire)
|
||||||
|
=(`1 (find chat wire))
|
||||||
|
==
|
||||||
|
~
|
||||||
|
`(pull-wire target wire)
|
||||||
::
|
::
|
||||||
++ pull-wire
|
++ pull-wire
|
||||||
|= pax=path
|
|= [=ship =wire]
|
||||||
^- (list card)
|
^- card
|
||||||
?> ?=(^ pax)
|
?: =(ship our.bol)
|
||||||
=/ shp (~(get by synced) t.pax)
|
[%pass wire %agent [our.bol %chat-store] %leave ~]
|
||||||
?~ shp ~
|
[%pass wire %agent [ship %chat-hook] %leave ~]
|
||||||
?: =(u.shp our.bol)
|
|
||||||
[%pass pax %agent [our.bol %chat-store] %leave ~]~
|
|
||||||
[%pass pax %agent [u.shp %chat-hook] %leave ~]~
|
|
||||||
--
|
--
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
:: chat-store: data store that holds linear sequences of chat messages
|
:: chat-store: data store that holds linear sequences of chat messages
|
||||||
::
|
::
|
||||||
/+ *chat-json, *chat-eval, default-agent, verb, dbug
|
/+ *chat-json, *chat-eval, default-agent, verb, dbug
|
||||||
|
~% %chat-store-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% state-zero
|
$% state-zero
|
||||||
|
state-one
|
||||||
|
state-two
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ state-zero
|
+$ state-zero [%0 =inbox]
|
||||||
$: %0
|
+$ state-one [%1 =inbox]
|
||||||
=inbox
|
+$ state-two [%2 =inbox]
|
||||||
==
|
|
||||||
::
|
::
|
||||||
+$ diff
|
+$ diff
|
||||||
$% [%chat-initial inbox]
|
$% [%chat-initial inbox]
|
||||||
@ -19,13 +21,14 @@
|
|||||||
==
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
=| state-zero
|
=| state-two
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
%+ verb |
|
%+ verb |
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|
~% %chat-store-agent-core ..peek-x-envelopes ~
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
chat-core +>
|
chat-core +>
|
||||||
@ -35,10 +38,19 @@
|
|||||||
++ on-init on-init:def
|
++ on-init on-init:def
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old=vase
|
|= old-vase=vase
|
||||||
`this(state !<(state-zero old))
|
=/ old !<(versioned-state old-vase)
|
||||||
|
?: ?=(%2 -.old)
|
||||||
|
[~ this(state old)]
|
||||||
|
=/ reversed-inbox=^inbox
|
||||||
|
%- ~(run by inbox.old)
|
||||||
|
|= =mailbox
|
||||||
|
^- ^mailbox
|
||||||
|
[config.mailbox (flop envelopes.mailbox)]
|
||||||
|
[~ this(state [%2 reversed-inbox])]
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|
~/ %chat-store-poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?> (team:title our.bowl src.bowl)
|
?> (team:title our.bowl src.bowl)
|
||||||
@ -50,10 +62,11 @@
|
|||||||
[cards this]
|
[cards this]
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
|
~/ %chat-store-watch
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?> (team:title our.bowl src.bowl)
|
|
||||||
|^
|
|^
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
=/ cards=(list card)
|
=/ cards=(list card)
|
||||||
?+ path (on-watch:def path)
|
?+ path (on-watch:def path)
|
||||||
[%keys ~] (give %chat-update !>([%keys ~(key by inbox)]))
|
[%keys ~] (give %chat-update !>([%keys ~(key by inbox)]))
|
||||||
@ -62,8 +75,7 @@
|
|||||||
[%updates ~] ~
|
[%updates ~] ~
|
||||||
[%mailbox @ *]
|
[%mailbox @ *]
|
||||||
?> (~(has by inbox) t.path)
|
?> (~(has by inbox) t.path)
|
||||||
=/ =ship (slav %p i.t.path)
|
(give %chat-update !>([%create t.path]))
|
||||||
(give %chat-update !>([%create ship t.t.path]))
|
|
||||||
==
|
==
|
||||||
[cards this]
|
[cards this]
|
||||||
::
|
::
|
||||||
@ -75,6 +87,7 @@
|
|||||||
::
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
++ on-peek
|
++ on-peek
|
||||||
|
~/ %chat-store-peek
|
||||||
|= =path
|
|= =path
|
||||||
^- (unit (unit cage))
|
^- (unit (unit cage))
|
||||||
?+ path (on-peek:def path)
|
?+ path (on-peek:def path)
|
||||||
@ -102,6 +115,7 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
::
|
::
|
||||||
|
~% %chat-store-library ..card ~
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
::
|
::
|
||||||
++ peek-x-envelopes
|
++ peek-x-envelopes
|
||||||
@ -153,28 +167,30 @@
|
|||||||
?- -.action
|
?- -.action
|
||||||
%create (handle-create action)
|
%create (handle-create action)
|
||||||
%delete (handle-delete action)
|
%delete (handle-delete action)
|
||||||
%message (handle-message action)
|
|
||||||
%messages (handle-messages action)
|
|
||||||
%read (handle-read action)
|
%read (handle-read action)
|
||||||
|
%messages (handle-messages action)
|
||||||
|
%message
|
||||||
|
?. =(our.bol author.envelope.action)
|
||||||
|
(handle-message action)
|
||||||
|
=^ message-moves state (handle-message action)
|
||||||
|
=^ read-moves state (handle-read [%read path.action])
|
||||||
|
[(weld message-moves read-moves) state]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ handle-create
|
++ handle-create
|
||||||
|= act=chat-action
|
|= act=chat-action
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?> ?=(%create -.act)
|
?> ?=(%create -.act)
|
||||||
=/ pax [(scot %p ship.act) path.act]
|
?: (~(has by inbox) path.act) [~ state]
|
||||||
?: (~(has by inbox) pax)
|
:- (send-diff path.act act)
|
||||||
[~ state]
|
state(inbox (~(put by inbox) path.act *mailbox))
|
||||||
:- (send-diff pax act)
|
|
||||||
state(inbox (~(put by inbox) pax *mailbox))
|
|
||||||
::
|
::
|
||||||
++ handle-delete
|
++ handle-delete
|
||||||
|= act=chat-action
|
|= act=chat-action
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?> ?=(%delete -.act)
|
?> ?=(%delete -.act)
|
||||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||||
?~ mailbox
|
?~ mailbox [~ state]
|
||||||
[~ state]
|
|
||||||
:- (send-diff path.act act)
|
:- (send-diff path.act act)
|
||||||
state(inbox (~(del by inbox) path.act))
|
state(inbox (~(del by inbox) path.act))
|
||||||
::
|
::
|
||||||
@ -186,8 +202,8 @@
|
|||||||
?~ mailbox
|
?~ mailbox
|
||||||
[~ state]
|
[~ state]
|
||||||
=. letter.envelope.act (evaluate-letter [author letter]:envelope.act)
|
=. letter.envelope.act (evaluate-letter [author letter]:envelope.act)
|
||||||
=. u.mailbox (append-envelope u.mailbox envelope.act)
|
=^ envelope u.mailbox (prepend-envelope u.mailbox envelope.act)
|
||||||
:- (send-diff path.act act)
|
:- (send-diff path.act act(envelope envelope))
|
||||||
state(inbox (~(put by inbox) path.act u.mailbox))
|
state(inbox (~(put by inbox) path.act u.mailbox))
|
||||||
::
|
::
|
||||||
++ handle-messages
|
++ handle-messages
|
||||||
@ -197,20 +213,16 @@
|
|||||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||||
?~ mailbox
|
?~ mailbox
|
||||||
[~ state]
|
[~ state]
|
||||||
|
=. envelopes.act (flop envelopes.act)
|
||||||
=/ evaluated-envelopes=(list envelope) ~
|
=/ evaluated-envelopes=(list envelope) ~
|
||||||
|- ^- (quip card _state)
|
|- ^- (quip card _state)
|
||||||
?~ envelopes.act
|
?~ envelopes.act
|
||||||
:_ state(inbox (~(put by inbox) path.act u.mailbox))
|
:_ state(inbox (~(put by inbox) path.act u.mailbox))
|
||||||
%+ send-diff path.act
|
%+ send-diff path.act
|
||||||
:* %messages
|
[%messages path.act 0 (lent evaluated-envelopes) evaluated-envelopes]
|
||||||
path.act
|
|
||||||
(sub length.config.u.mailbox (lent evaluated-envelopes))
|
|
||||||
length.config.u.mailbox
|
|
||||||
evaluated-envelopes
|
|
||||||
==
|
|
||||||
=. letter.i.envelopes.act (evaluate-letter [author letter]:i.envelopes.act)
|
=. letter.i.envelopes.act (evaluate-letter [author letter]:i.envelopes.act)
|
||||||
=. evaluated-envelopes (snoc evaluated-envelopes i.envelopes.act)
|
=^ envelope u.mailbox (prepend-envelope u.mailbox i.envelopes.act)
|
||||||
=. u.mailbox (append-envelope u.mailbox i.envelopes.act)
|
=. evaluated-envelopes [envelope evaluated-envelopes]
|
||||||
$(envelopes.act t.envelopes.act)
|
$(envelopes.act t.envelopes.act)
|
||||||
::
|
::
|
||||||
++ handle-read
|
++ handle-read
|
||||||
@ -236,14 +248,14 @@
|
|||||||
letter(output (eval bol hoon))
|
letter(output (eval bol hoon))
|
||||||
letter
|
letter
|
||||||
::
|
::
|
||||||
++ append-envelope
|
++ prepend-envelope
|
||||||
|= [=mailbox =envelope]
|
|= [=mailbox =envelope]
|
||||||
^- ^mailbox
|
^+ [envelope mailbox]
|
||||||
=. number.envelope +(length.config.mailbox)
|
=. number.envelope +(length.config.mailbox)
|
||||||
=: length.config.mailbox +(length.config.mailbox)
|
=: length.config.mailbox +(length.config.mailbox)
|
||||||
envelopes.mailbox (snoc envelopes.mailbox envelope)
|
envelopes.mailbox [envelope envelopes.mailbox]
|
||||||
==
|
==
|
||||||
mailbox
|
[envelope mailbox]
|
||||||
::
|
::
|
||||||
++ update-subscribers
|
++ update-subscribers
|
||||||
|= [pax=path update=chat-update]
|
|= [pax=path update=chat-update]
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
/- *permission-store,
|
/- *permission-store,
|
||||||
*permission-hook,
|
*permission-hook,
|
||||||
*group-store,
|
*group-store,
|
||||||
|
*invite-store,
|
||||||
|
*metadata-store,
|
||||||
*permission-group-hook,
|
*permission-group-hook,
|
||||||
*chat-hook
|
*chat-hook,
|
||||||
|
*metadata-hook
|
||||||
/+ *server, *chat-json, default-agent, verb, dbug
|
/+ *server, *chat-json, default-agent, verb, dbug
|
||||||
/= index
|
/= index
|
||||||
/^ octs
|
/^ octs
|
||||||
@ -39,6 +42,7 @@
|
|||||||
/^ (map knot @)
|
/^ (map knot @)
|
||||||
/: /===/app/chat/img /_ /png/
|
/: /===/app/chat/img /_ /png/
|
||||||
::
|
::
|
||||||
|
~% %chat-view-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
::
|
::
|
||||||
@ -51,10 +55,11 @@
|
|||||||
[%permission-group-hook-action permission-group-hook-action]
|
[%permission-group-hook-action permission-group-hook-action]
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
%- agent:dbug
|
|
||||||
%+ verb |
|
%+ verb |
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|
~% %chat-view-agent-core ..poke-handle-http-request ~
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
chat-core +>
|
chat-core +>
|
||||||
@ -63,13 +68,14 @@
|
|||||||
::
|
::
|
||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
=/ launcha [%launch-action !>([%chat-view /configs '/~chat/js/tile.js'])]
|
=/ launcha [%launch-action !>([%add %chat-view /configs '/~chat/js/tile.js'])]
|
||||||
:_ this
|
:_ this
|
||||||
:~ [%pass /updates %agent [our.bol %chat-store] %watch /updates]
|
:~ [%pass /updates %agent [our.bol %chat-store] %watch /updates]
|
||||||
[%pass / %arvo %e %connect [~ /'~chat'] %chat-view]
|
[%pass / %arvo %e %connect [~ /'~chat'] %chat-view]
|
||||||
[%pass /chat-view %agent [our.bol %launch] %poke launcha]
|
[%pass /chat-view %agent [our.bol %launch] %poke launcha]
|
||||||
==
|
==
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|
~/ %chat-view-poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?> (team:title our.bol src.bol)
|
?> (team:title our.bol src.bol)
|
||||||
@ -91,6 +97,7 @@
|
|||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
|
~/ %chat-view-watch
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?> (team:title our.bol src.bol)
|
?> (team:title our.bol src.bol)
|
||||||
@ -98,7 +105,7 @@
|
|||||||
?: ?=([%http-response *] path)
|
?: ?=([%http-response *] path)
|
||||||
[~ this]
|
[~ this]
|
||||||
?: =(/primary path)
|
?: =(/primary path)
|
||||||
:: create inbox with 100 messages max per mailbox and send that along
|
:: create inbox with 20 messages max per mailbox and send that along
|
||||||
:: then quit the subscription
|
:: then quit the subscription
|
||||||
:_ this
|
:_ this
|
||||||
[%give %fact ~ %json !>((inbox-to-json truncated-inbox-scry))]~
|
[%give %fact ~ %json !>((inbox-to-json truncated-inbox-scry))]~
|
||||||
@ -106,24 +113,19 @@
|
|||||||
[[%give %fact ~ %json !>(*json)]~ this]
|
[[%give %fact ~ %json !>(*json)]~ this]
|
||||||
(on-watch:def path)
|
(on-watch:def path)
|
||||||
::
|
::
|
||||||
|
++ message-limit 20
|
||||||
|
::
|
||||||
++ truncated-inbox-scry
|
++ truncated-inbox-scry
|
||||||
^- inbox
|
^- inbox
|
||||||
=/ =inbox .^(inbox %gx /=chat-store/(scot %da now.bol)/all/noun)
|
=/ =inbox .^(inbox %gx /=chat-store/(scot %da now.bol)/all/noun)
|
||||||
%- ~(run by inbox)
|
%- ~(run by inbox)
|
||||||
|= =mailbox
|
|= =mailbox
|
||||||
^- ^mailbox
|
^- ^mailbox
|
||||||
[config.mailbox (truncate-envelopes envelopes.mailbox)]
|
[config.mailbox (scag message-limit envelopes.mailbox)]
|
||||||
::
|
|
||||||
++ truncate-envelopes
|
|
||||||
|= envelopes=(list envelope)
|
|
||||||
^- (list envelope)
|
|
||||||
=/ length (lent envelopes)
|
|
||||||
?: (lth length 100)
|
|
||||||
envelopes
|
|
||||||
(swag [(sub length 100) 100] envelopes)
|
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ on-agent
|
++ on-agent
|
||||||
|
~/ %chat-view-agent
|
||||||
|= [=wire =sign:agent:gall]
|
|= [=wire =sign:agent:gall]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?+ -.sign (on-agent:def wire sign)
|
?+ -.sign (on-agent:def wire sign)
|
||||||
@ -140,6 +142,7 @@
|
|||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-arvo
|
++ on-arvo
|
||||||
|
~/ %chat-view-arvo
|
||||||
|= [=wire =sign-arvo]
|
|= [=wire =sign-arvo]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?. ?=(%bound +<.sign-arvo)
|
?. ?=(%bound +<.sign-arvo)
|
||||||
@ -154,6 +157,7 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
::
|
::
|
||||||
|
~% %chat-view-library ..card ~
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
::
|
::
|
||||||
++ poke-handle-http-request
|
++ poke-handle-http-request
|
||||||
@ -188,53 +192,290 @@
|
|||||||
++ poke-json
|
++ poke-json
|
||||||
|= jon=json
|
|= jon=json
|
||||||
^- (list card)
|
^- (list card)
|
||||||
?. =(src.bol our.bol)
|
?> (team:title our.bol src.bol)
|
||||||
~
|
|
||||||
(poke-chat-view-action (json-to-view-action jon))
|
(poke-chat-view-action (json-to-view-action jon))
|
||||||
::
|
::
|
||||||
++ poke-chat-view-action
|
++ poke-chat-view-action
|
||||||
|= act=chat-view-action
|
|= act=chat-view-action
|
||||||
^- (list card)
|
^- (list card)
|
||||||
?. =(src.bol our.bol)
|
|^
|
||||||
~
|
?> (team:title our.bol src.bol)
|
||||||
?- -.act
|
?- -.act
|
||||||
%create
|
%create
|
||||||
=/ pax [(scot %p our.bol) path.act]
|
?> ?=(^ app-path.act)
|
||||||
=/ group-read=path [%chat (weld pax /read)]
|
?> |(=(group-path.act app-path.act) =(~(tap in members.act) ~))
|
||||||
=/ group-write=path [%chat (weld pax /write)]
|
?^ (chat-scry app-path.act)
|
||||||
|
~& %chat-already-exists
|
||||||
|
~
|
||||||
%- zing
|
%- zing
|
||||||
:~ :~ (group-poke [%bundle group-read])
|
:~ (create-chat app-path.act allow-history.act)
|
||||||
(group-poke [%bundle group-write])
|
%- create-group
|
||||||
(group-poke [%add read.act group-read])
|
:* group-path.act
|
||||||
(group-poke [%add write.act group-write])
|
app-path.act
|
||||||
(chat-poke [%create our.bol path.act])
|
security.act
|
||||||
(chat-hook-poke [%add-owned pax security.act allow-history.act])
|
members.act
|
||||||
==
|
title.act
|
||||||
(create-security [%chat pax] security.act)
|
description.act
|
||||||
:~ (permission-hook-poke [%add-owned group-read group-read])
|
|
||||||
(permission-hook-poke [%add-owned group-write group-read])
|
|
||||||
==
|
==
|
||||||
|
(create-metadata title.act description.act group-path.act app-path.act)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%delete
|
%delete
|
||||||
=/ group-read [%chat (weld path.act /read)]
|
?> ?=(^ app-path.act)
|
||||||
=/ group-write [%chat (weld path.act /write)]
|
:: always just delete the chat from chat-store
|
||||||
:~ (chat-hook-poke [%remove path.act])
|
::
|
||||||
(permission-hook-poke [%remove group-read])
|
:+ (chat-hook-poke [%remove app-path.act])
|
||||||
(permission-hook-poke [%remove group-write])
|
(chat-poke [%delete app-path.act])
|
||||||
(group-poke [%unbundle group-read])
|
:: if we still have metadata for the chat, remove it, and the associated
|
||||||
(group-poke [%unbundle group-write])
|
:: group if it's unmanaged
|
||||||
(chat-poke [%delete path.act])
|
::
|
||||||
|
:: we aren't guaranteed to have metadata: the chat might have been
|
||||||
|
:: deleted by the host, which pushes metadata deletion down to us.
|
||||||
|
::
|
||||||
|
=/ group-path=(unit path)
|
||||||
|
(maybe-group-from-chat app-path.act)
|
||||||
|
?~ group-path ~
|
||||||
|
=* group u.group-path
|
||||||
|
%- zing
|
||||||
|
:~ ?. (is-creator group %chat app-path.act) ~
|
||||||
|
[(metadata-poke [%remove group [%chat app-path.act]])]~
|
||||||
|
::
|
||||||
|
?: (is-managed group) ~
|
||||||
|
:~ (group-poke [%unbundle group])
|
||||||
|
(metadata-hook-poke [%remove group])
|
||||||
|
(metadata-store-poke [%remove group [%chat app-path.act]])
|
||||||
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%join
|
%join
|
||||||
=/ group-read [%chat (scot %p ship.act) (weld path.act /read)]
|
=/ group-path
|
||||||
=/ group-write [%chat (scot %p ship.act) (weld path.act /write)]
|
?. (is-managed app-path.act) app-path.act
|
||||||
:~ (chat-hook-poke [%add-synced ship.act path.act ask-history.act])
|
(group-from-chat app-path.act)
|
||||||
(permission-hook-poke [%add-synced ship.act group-write])
|
:~ (chat-hook-poke [%add-synced ship.act app-path.act ask-history.act])
|
||||||
(permission-hook-poke [%add-synced ship.act group-read])
|
(permission-hook-poke [%add-synced ship.act group-path])
|
||||||
|
(metadata-hook-poke [%add-synced ship.act group-path])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%groupify
|
||||||
|
?> ?=([%'~' ^] app-path.act)
|
||||||
|
:: retrieve old data
|
||||||
|
::
|
||||||
|
=/ data=(unit mailbox)
|
||||||
|
(scry-for (unit mailbox) %chat-store [%mailbox app-path.act])
|
||||||
|
?~ data
|
||||||
|
~& [%cannot-groupify-nonexistent app-path.act]
|
||||||
|
~
|
||||||
|
=/ permission=(unit permission)
|
||||||
|
(scry-for (unit permission) %permission-store [%permission app-path.act])
|
||||||
|
?: |(?=(~ permission) ?=(%black kind.u.permission))
|
||||||
|
~& [%cannot-groupify-blacklist app-path.act]
|
||||||
|
~
|
||||||
|
=/ =metadata
|
||||||
|
=- (fall - *metadata)
|
||||||
|
%^ scry-for (unit metadata)
|
||||||
|
%metadata-store
|
||||||
|
=/ encoded-path=@ta
|
||||||
|
(scot %t (spat app-path.act))
|
||||||
|
/metadata/[encoded-path]/chat/[encoded-path]
|
||||||
|
:: figure out new data
|
||||||
|
::
|
||||||
|
=/ chat-path=^path (slag 1 `path`app-path.act)
|
||||||
|
:: group-path: the group to associate with the chat
|
||||||
|
:: members: members of group, if it's new
|
||||||
|
:: new-members: new members of group, if it already exists
|
||||||
|
::
|
||||||
|
=/ [group-path=path members=(set ship) new-members=(set ship)]
|
||||||
|
?~ existing.act
|
||||||
|
[chat-path who.u.permission ~]
|
||||||
|
:+ group-path.u.existing.act
|
||||||
|
~
|
||||||
|
?. inclusive.u.existing.act ~
|
||||||
|
%- ~(dif in who.u.permission)
|
||||||
|
~| [%groupifying-with-nonexistent-group group-path.u.existing.act]
|
||||||
|
%- need
|
||||||
|
(group-scry group-path.u.existing.act)
|
||||||
|
:: make changes
|
||||||
|
::
|
||||||
|
;: weld
|
||||||
|
:: delete the old chat
|
||||||
|
::
|
||||||
|
(poke-chat-view-action %delete app-path.act)
|
||||||
|
::
|
||||||
|
:: create the new chat. if needed, creates the new group.
|
||||||
|
::
|
||||||
|
%- poke-chat-view-action
|
||||||
|
:* %create
|
||||||
|
title.metadata
|
||||||
|
description.metadata
|
||||||
|
chat-path
|
||||||
|
group-path
|
||||||
|
%village
|
||||||
|
members
|
||||||
|
&
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: if needed, add members to the existing group
|
||||||
|
::
|
||||||
|
?~ new-members ~
|
||||||
|
[(group-poke [%add new-members group-path])]~
|
||||||
|
::
|
||||||
|
:: import messages into the new chat
|
||||||
|
::
|
||||||
|
[(chat-poke %messages chat-path envelopes.u.data)]~
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
|
::
|
||||||
|
++ create-chat
|
||||||
|
|= [=path history=?]
|
||||||
|
^- (list card)
|
||||||
|
:~ (chat-poke [%create path])
|
||||||
|
(chat-hook-poke [%add-owned path history])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ create-group
|
||||||
|
|= [=path app-path=path sec=rw-security ships=(set ship) title=@t desc=@t]
|
||||||
|
^- (list card)
|
||||||
|
?^ (group-scry path) ~
|
||||||
|
:: do not create a managed group if this is a sig path or a blacklist
|
||||||
|
::
|
||||||
|
?: =(sec %channel)
|
||||||
|
:~ (group-poke [%bundle path])
|
||||||
|
(create-security path sec)
|
||||||
|
(permission-hook-poke [%add-owned path path])
|
||||||
|
==
|
||||||
|
?: (is-managed path)
|
||||||
|
~[(contact-view-poke [%create path ships title desc])]
|
||||||
|
%+ welp
|
||||||
|
:~ (group-poke [%bundle path])
|
||||||
|
(group-poke [%add ships path])
|
||||||
|
(create-security path sec)
|
||||||
|
(permission-hook-poke [%add-owned path path])
|
||||||
|
==
|
||||||
|
%- zing
|
||||||
|
%+ turn ~(tap in ships)
|
||||||
|
|= =ship
|
||||||
|
?: =(ship our.bol) ~
|
||||||
|
[(send-invite app-path ship)]~
|
||||||
|
::
|
||||||
|
++ create-security
|
||||||
|
|= [pax=path sec=rw-security]
|
||||||
|
^- card
|
||||||
|
?+ sec !!
|
||||||
|
%channel
|
||||||
|
(perm-group-hook-poke [%associate pax [[pax %black] ~ ~]])
|
||||||
|
::
|
||||||
|
%village
|
||||||
|
(perm-group-hook-poke [%associate pax [[pax %white] ~ ~]])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ create-metadata
|
||||||
|
|= [title=@t description=@t group-path=path app-path=path]
|
||||||
|
^- (list card)
|
||||||
|
=/ =metadata
|
||||||
|
%* . *metadata
|
||||||
|
title title
|
||||||
|
description description
|
||||||
|
date-created now.bol
|
||||||
|
creator
|
||||||
|
%+ slav %p
|
||||||
|
?: (is-managed app-path) (snag 0 app-path)
|
||||||
|
(snag 1 app-path)
|
||||||
|
==
|
||||||
|
:~ (metadata-poke [%add group-path [%chat app-path] metadata])
|
||||||
|
(metadata-hook-poke [%add-owned group-path])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ contact-view-poke
|
||||||
|
|= act=[%create =path ships=(set ship) title=@t description=@t]
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %contact-view] %poke %contact-view-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-poke
|
||||||
|
|= act=metadata-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %metadata-hook] %poke %metadata-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-store-poke
|
||||||
|
|= act=metadata-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %metadata-store] %poke %metadata-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-hook-poke
|
||||||
|
|= act=metadata-hook-action
|
||||||
|
^- card
|
||||||
|
:* %pass / %agent
|
||||||
|
[our.bol %metadata-hook]
|
||||||
|
%poke %metadata-hook-action
|
||||||
|
!>(act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ send-invite
|
||||||
|
|= [=path =ship]
|
||||||
|
^- card
|
||||||
|
=/ =invite
|
||||||
|
:* our.bol %chat-hook
|
||||||
|
path ship ''
|
||||||
|
==
|
||||||
|
=/ act=invite-action [%invite /chat (shaf %msg-uid eny.bol) invite]
|
||||||
|
[%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)]
|
||||||
|
::
|
||||||
|
++ chat-scry
|
||||||
|
|= pax=path
|
||||||
|
^- (unit mailbox)
|
||||||
|
=. pax ;:(weld /=chat-store/(scot %da now.bol)/mailbox pax /noun)
|
||||||
|
.^((unit mailbox) %gx pax)
|
||||||
|
::
|
||||||
|
++ maybe-group-from-chat
|
||||||
|
|= app-path=path
|
||||||
|
^- (unit path)
|
||||||
|
?. .^(? %gu (scot %p our.bol) %metadata-store (scot %da now.bol) ~)
|
||||||
|
?: ?=([@ ^] app-path)
|
||||||
|
~& [%assuming-ported-legacy-chat app-path]
|
||||||
|
`[%'~' app-path]
|
||||||
|
~& [%weird-chat app-path]
|
||||||
|
!!
|
||||||
|
=/ resource-indices
|
||||||
|
.^ (jug resource group-path)
|
||||||
|
%gy
|
||||||
|
(scot %p our.bol)
|
||||||
|
%metadata-store
|
||||||
|
(scot %da now.bol)
|
||||||
|
/resource-indices
|
||||||
|
==
|
||||||
|
=/ groups=(set path)
|
||||||
|
%+ fall
|
||||||
|
(~(get by resource-indices) [%chat app-path])
|
||||||
|
*(set path)
|
||||||
|
?~ groups ~
|
||||||
|
`n.groups
|
||||||
|
::
|
||||||
|
++ group-from-chat
|
||||||
|
(cork maybe-group-from-chat need)
|
||||||
|
::
|
||||||
|
++ is-managed
|
||||||
|
|= =path
|
||||||
|
^- ?
|
||||||
|
?> ?=(^ path)
|
||||||
|
!=(i.path '~')
|
||||||
|
::
|
||||||
|
++ is-creator
|
||||||
|
|= [group-path=path app-name=@ta app-path=path]
|
||||||
|
^- ?
|
||||||
|
=/ meta=(unit metadata)
|
||||||
|
.^ (unit metadata)
|
||||||
|
%gx
|
||||||
|
(scot %p our.bol)
|
||||||
|
%metadata-store
|
||||||
|
(scot %da now.bol)
|
||||||
|
%metadata
|
||||||
|
(scot %t (spat group-path))
|
||||||
|
app-name
|
||||||
|
(scot %t (spat app-path))
|
||||||
|
/noun
|
||||||
|
==
|
||||||
|
?~ meta !!
|
||||||
|
=(our.bol creator.u.meta)
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ diff-chat-update
|
++ diff-chat-update
|
||||||
|= upd=chat-update
|
|= upd=chat-update
|
||||||
@ -257,6 +498,11 @@
|
|||||||
^- card
|
^- card
|
||||||
[%pass / %agent [our.bol %group-store] %poke %group-action !>(act)]
|
[%pass / %agent [our.bol %group-store] %poke %group-action !>(act)]
|
||||||
::
|
::
|
||||||
|
++ permission-poke
|
||||||
|
|= act=permission-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %permission-store] %poke %permission-action !>(act)]
|
||||||
|
::
|
||||||
++ chat-hook-poke
|
++ chat-hook-poke
|
||||||
|= act=chat-hook-action
|
|= act=chat-hook-action
|
||||||
^- card
|
^- card
|
||||||
@ -279,37 +525,24 @@
|
|||||||
++ envelope-scry
|
++ envelope-scry
|
||||||
|= pax=path
|
|= pax=path
|
||||||
^- (list envelope)
|
^- (list envelope)
|
||||||
=. pax ;:(weld /=chat-store/(scot %da now.bol)/envelopes pax /noun)
|
(scry-for (list envelope) %chat-store [%envelopes pax])
|
||||||
.^((list envelope) %gx pax)
|
|
||||||
::
|
::
|
||||||
++ configs-scry
|
++ configs-scry
|
||||||
^- chat-configs
|
^- chat-configs
|
||||||
.^(chat-configs %gx /=chat-store/(scot %da now.bol)/configs/noun)
|
(scry-for chat-configs %chat-store /configs)
|
||||||
::
|
::
|
||||||
++ create-security
|
++ group-scry
|
||||||
|= [pax=path sec=rw-security]
|
|= pax=path
|
||||||
^- (list card)
|
^- (unit group)
|
||||||
=/ read (weld pax /read)
|
(scry-for (unit group) %group-store pax)
|
||||||
=/ write (weld pax /write)
|
::
|
||||||
?- sec
|
++ scry-for
|
||||||
%channel
|
|* [=mold app=term =path]
|
||||||
:~ (perm-group-hook-poke [%associate read [[read %black] ~ ~]])
|
.^ mold
|
||||||
(perm-group-hook-poke [%associate write [[write %black] ~ ~]])
|
%gx
|
||||||
==
|
(scot %p our.bol)
|
||||||
::
|
app
|
||||||
%village
|
(scot %da now.bol)
|
||||||
:~ (perm-group-hook-poke [%associate read [[read %white] ~ ~]])
|
(snoc `^path`path %noun)
|
||||||
(perm-group-hook-poke [%associate write [[write %white] ~ ~]])
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%journal
|
|
||||||
:~ (perm-group-hook-poke [%associate read [[read %black] ~ ~]])
|
|
||||||
(perm-group-hook-poke [%associate write [[write %white] ~ ~]])
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%mailbox
|
|
||||||
:~ (perm-group-hook-poke [%associate read [[read %white] ~ ~]])
|
|
||||||
(perm-group-hook-poke [%associate write [[write %black] ~ ~]])
|
|
||||||
==
|
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
|
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 861 B After Width: | Height: | Size: 1.4 KiB |
BIN
pkg/arvo/app/chat/img/CodeEval.png
Normal file
After Width: | Height: | Size: 611 B |
Before Width: | Height: | Size: 255 B |
BIN
pkg/arvo/app/chat/img/ImageUpload.png
Normal file
After Width: | Height: | Size: 865 B |
BIN
pkg/arvo/app/chat/img/Spinner.png
Normal file
After Width: | Height: | Size: 679 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 1.5 KiB |
BIN
pkg/arvo/app/chat/img/search.png
Normal file
After Width: | Height: | Size: 951 B |
@ -22,9 +22,10 @@
|
|||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root" />
|
<div id="root"/>
|
||||||
<script src="/~/channel/channel.js"></script>
|
<script src="/~channel/channel.js"></script>
|
||||||
<script src="/~modulo/session.js"></script>
|
<script src="/~modulo/session.js"></script>
|
||||||
<script src="/~chat/js/index.js"></script>
|
<script src="/~chat/js/index.js"></script>
|
||||||
|
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -417,14 +417,17 @@
|
|||||||
:* to
|
:* to
|
||||||
(mul windup-years yer:yo)
|
(mul windup-years yer:yo)
|
||||||
stars
|
stars
|
||||||
(div (mul unlock-years yer:yo) stars)
|
|
||||||
1
|
1
|
||||||
|
(div (mul unlock-years yer:yo) stars)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ register-conditional
|
++ register-conditional
|
||||||
|= [to=address [b1=@ud b2=@ud b3=@ud] unlock-years-per-batch=@ud]
|
|= [to=address [b1=@ud b2=@ud b3=@ud] unlock-years-per-batch=@ud]
|
||||||
%- register-conditional:dat
|
%- register-conditional:dat
|
||||||
=- [`address`to b1 b2 b3 `@ud`- 1]
|
:* to
|
||||||
(div (mul unlock-years-per-batch yer:yo) :(add b1 b2 b3))
|
b1 b2 b3
|
||||||
|
1
|
||||||
|
(div (mul unlock-years-per-batch yer:yo) :(add b1 b2 b3))
|
||||||
|
==
|
||||||
::
|
::
|
||||||
--
|
--
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/+ *server, default-agent, verb
|
/+ *server, default-agent, verb, dbug
|
||||||
/= tile-js
|
/= tile-js
|
||||||
/^ octs
|
/^ octs
|
||||||
/; as-octs:mimes:html
|
/; as-octs:mimes:html
|
||||||
@ -8,7 +8,18 @@
|
|||||||
==
|
==
|
||||||
=, format
|
=, format
|
||||||
::
|
::
|
||||||
|
|%
|
||||||
|
::
|
||||||
|
+$ card card:agent:gall
|
||||||
|
+$ versioned-state
|
||||||
|
$% state-zero
|
||||||
|
==
|
||||||
|
+$ state-zero [%0 data=json]
|
||||||
|
--
|
||||||
%+ verb |
|
%+ verb |
|
||||||
|
%- agent:dbug
|
||||||
|
=| state-zero
|
||||||
|
=* state -
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
@ -17,20 +28,28 @@
|
|||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card:agent:gall _this)
|
^- (quip card:agent:gall _this)
|
||||||
=/ launcha
|
=/ launcha
|
||||||
[%launch-action !>([%clock /tile '/~clock/js/tile.js'])]
|
[%launch-action !>([%add %clock /clocktile '/~clock/js/tile.js'])]
|
||||||
:_ this
|
:_ this
|
||||||
:~ [%pass / %arvo %e %connect [~ /'~clock'] %clock]
|
:~ [%pass / %arvo %e %connect [~ /'~clock'] %clock]
|
||||||
[%pass /clock %agent [our.bowl %launch] %poke launcha]
|
[%pass /clock %agent [our.bowl %launch] %poke launcha]
|
||||||
==
|
==
|
||||||
:: bootstrapping to get %goad started OTA
|
:: bootstrapping to get %goad started OTA
|
||||||
::
|
::
|
||||||
++ on-save !>(%2)
|
++ on-save !>(%3)
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old-state=vase
|
|= old-state=vase
|
||||||
=/ old !<(?(~ %1 %2) old-state)
|
^- (quip card _this)
|
||||||
|
=/ old !<(?(~ %1 %2 %3) old-state)
|
||||||
=^ cards this
|
=^ cards this
|
||||||
?: ?=(%2 old)
|
?: ?=(%3 old)
|
||||||
`this
|
`this
|
||||||
|
?: ?=(%2 old)
|
||||||
|
:: ensure launch is set up to listen to us correctly
|
||||||
|
::
|
||||||
|
=/ launcha
|
||||||
|
[%launch-action !>([%add %clock /clocktile '/~clock/js/tile.js'])]
|
||||||
|
:_ this
|
||||||
|
[%pass /clock %agent [our.bowl %launch] %poke launcha]~
|
||||||
:_ this :_ ~
|
:_ this :_ ~
|
||||||
[%pass /behn %arvo %b %wait +(now.bowl)]
|
[%pass /behn %arvo %b %wait +(now.bowl)]
|
||||||
::
|
::
|
||||||
@ -39,6 +58,9 @@
|
|||||||
++ on-poke
|
++ on-poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
^- (quip card:agent:gall _this)
|
^- (quip card:agent:gall _this)
|
||||||
|
|^
|
||||||
|
?: ?=(%json mark)
|
||||||
|
(poke-json !<(json vase))
|
||||||
?. ?=(%handle-http-request mark)
|
?. ?=(%handle-http-request mark)
|
||||||
(on-poke:def mark vase)
|
(on-poke:def mark vase)
|
||||||
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
|
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
|
||||||
@ -59,15 +81,23 @@
|
|||||||
?: =(name 'tile')
|
?: =(name 'tile')
|
||||||
(js-response:gen tile-js)
|
(js-response:gen tile-js)
|
||||||
not-found:gen
|
not-found:gen
|
||||||
|
::
|
||||||
|
++ poke-json
|
||||||
|
|= jon=json
|
||||||
|
^- (quip card:agent:gall _this)
|
||||||
|
=. data.state jon
|
||||||
|
:_ this
|
||||||
|
[%give %fact ~[/clocktile] %json !>(jon)]~
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
|= =path
|
|= =path
|
||||||
^- (quip card:agent:gall _this)
|
^- (quip card:agent:gall _this)
|
||||||
?: ?=([%http-response *] path)
|
?: ?=([%http-response *] path)
|
||||||
`this
|
`this
|
||||||
?. =(/tile path)
|
?. =(/clocktile path)
|
||||||
(on-watch:def path)
|
(on-watch:def path)
|
||||||
[[%give %fact ~ %json !>(*json)]~ this]
|
[[%give %fact ~ %json !>(data.state)]~ this]
|
||||||
::
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
++ on-peek on-peek:def
|
++ on-peek on-peek:def
|
||||||
|
483
pkg/arvo/app/contact-hook.hoon
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
:: contact-hook:
|
||||||
|
::
|
||||||
|
/- *group-store,
|
||||||
|
*group-hook,
|
||||||
|
*contact-hook,
|
||||||
|
*invite-store,
|
||||||
|
*metadata-hook,
|
||||||
|
*metadata-store
|
||||||
|
/+ *contact-json, default-agent, dbug
|
||||||
|
~% %contact-hook-top ..is ~
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
::
|
||||||
|
+$ versioned-state
|
||||||
|
$% state-zero
|
||||||
|
state-one
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ state-zero [%0 state-base]
|
||||||
|
+$ state-one [%1 state-base]
|
||||||
|
+$ state-base
|
||||||
|
$: =synced
|
||||||
|
invite-created=_|
|
||||||
|
==
|
||||||
|
--
|
||||||
|
=| state-one
|
||||||
|
=* state -
|
||||||
|
%- agent:dbug
|
||||||
|
^- agent:gall
|
||||||
|
=<
|
||||||
|
|_ bol=bowl:gall
|
||||||
|
+* this .
|
||||||
|
contact-core +>
|
||||||
|
cc ~(. contact-core bol)
|
||||||
|
def ~(. (default-agent this %|) bol)
|
||||||
|
::
|
||||||
|
++ on-init
|
||||||
|
^- (quip card _this)
|
||||||
|
:_ this(invite-created %.y)
|
||||||
|
:~ (invite-poke:cc [%create /contacts])
|
||||||
|
[%pass /inv %agent [our.bol %invite-store] %watch /invitatory/contacts]
|
||||||
|
[%pass /group %agent [our.bol %group-store] %watch /updates]
|
||||||
|
==
|
||||||
|
++ on-save !>(state)
|
||||||
|
++ on-load
|
||||||
|
|= old-vase=vase
|
||||||
|
^- (quip card _this)
|
||||||
|
=/ old !<(versioned-state old-vase)
|
||||||
|
?: ?=(%1 -.old)
|
||||||
|
[~ this(state old)]
|
||||||
|
=/ upgraded-state
|
||||||
|
%* . *state-one
|
||||||
|
synced synced
|
||||||
|
invite-created invite-created
|
||||||
|
==
|
||||||
|
:_ this(state upgraded-state)
|
||||||
|
[%pass /group %agent [our.bol %group-store] %watch /updates]~
|
||||||
|
::
|
||||||
|
++ on-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
^- (quip card _this)
|
||||||
|
=^ cards state
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
%json
|
||||||
|
(poke-json:cc !<(json vase))
|
||||||
|
::
|
||||||
|
%contact-action
|
||||||
|
(poke-contact-action:cc !<(contact-action vase))
|
||||||
|
::
|
||||||
|
%contact-hook-action
|
||||||
|
(poke-hook-action:cc !<(contact-hook-action vase))
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ path (on-watch:def path)
|
||||||
|
[%contacts *] [(watch-contacts:cc t.path) this]
|
||||||
|
[%synced *] [(watch-synced:cc t.path) this]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-agent
|
||||||
|
|= [=wire =sign:agent:gall]
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ -.sign (on-agent:def wire sign)
|
||||||
|
%kick [(kick:cc wire) this]
|
||||||
|
%watch-ack
|
||||||
|
=^ cards state
|
||||||
|
(watch-ack:cc wire p.sign)
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
%fact
|
||||||
|
?+ p.cage.sign (on-agent:def wire sign)
|
||||||
|
%contact-update
|
||||||
|
=^ cards state
|
||||||
|
(fact-contact-update:cc wire !<(contact-update q.cage.sign))
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
%group-update
|
||||||
|
=^ cards state
|
||||||
|
(fact-group-update:cc wire !<(group-update q.cage.sign))
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
%invite-update
|
||||||
|
=^ cards state
|
||||||
|
(fact-invite-update:cc wire !<(invite-update q.cage.sign))
|
||||||
|
[cards this]
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-peek on-peek:def
|
||||||
|
++ on-arvo on-arvo:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
||||||
|
::
|
||||||
|
|_ bol=bowl:gall
|
||||||
|
::
|
||||||
|
++ poke-json
|
||||||
|
|= jon=json
|
||||||
|
^- (quip card _state)
|
||||||
|
(poke-contact-action (json-to-action jon))
|
||||||
|
::
|
||||||
|
++ poke-contact-action
|
||||||
|
|= act=contact-action
|
||||||
|
^- (quip card _state)
|
||||||
|
:_ state
|
||||||
|
?+ -.act !!
|
||||||
|
%edit (handle-contact-action path.act ship.act act)
|
||||||
|
%add (handle-contact-action path.act ship.act act)
|
||||||
|
%remove (handle-contact-action path.act ship.act act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-contact-action
|
||||||
|
|= [=path =ship act=contact-action]
|
||||||
|
^- (list card)
|
||||||
|
:: local
|
||||||
|
?: (team:title our.bol src.bol)
|
||||||
|
?. (~(has by synced) path) ~
|
||||||
|
=/ shp ?:(=(path /~/default) our.bol (~(got by synced) path))
|
||||||
|
=/ appl ?:(=(shp our.bol) %contact-store %contact-hook)
|
||||||
|
[%pass / %agent [shp appl] %poke %contact-action !>(act)]~
|
||||||
|
:: foreign
|
||||||
|
=/ shp (~(got by synced) path)
|
||||||
|
?. |(=(shp our.bol) =(src.bol ship)) ~
|
||||||
|
:: scry group to check if ship is a member
|
||||||
|
=/ =group (need (group-scry path))
|
||||||
|
?. (~(has in group) shp) ~
|
||||||
|
[%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]~
|
||||||
|
::
|
||||||
|
++ poke-hook-action
|
||||||
|
|= act=contact-hook-action
|
||||||
|
^- (quip card _state)
|
||||||
|
?- -.act
|
||||||
|
%add-owned
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
=/ contact-path [%contacts path.act]
|
||||||
|
?: (~(has by synced) path.act)
|
||||||
|
[~ state]
|
||||||
|
=. synced (~(put by synced) path.act our.bol)
|
||||||
|
:_ state
|
||||||
|
:~ [%pass contact-path %agent [our.bol %contact-store] %watch contact-path]
|
||||||
|
[%give %fact [/synced]~ %contact-hook-update !>([%initial synced])]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%add-synced
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
?: (~(has by synced) path.act) [~ state]
|
||||||
|
=. synced (~(put by synced) path.act ship.act)
|
||||||
|
=/ contact-path [%contacts path.act]
|
||||||
|
:_ state
|
||||||
|
:~ [%pass contact-path %agent [ship.act %contact-hook] %watch contact-path]
|
||||||
|
[%give %fact [/synced]~ %contact-hook-update !>([%initial synced])]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
=/ ship (~(get by synced) path.act)
|
||||||
|
?~ ship [~ state]
|
||||||
|
?: &(=(u.ship our.bol) (team:title our.bol src.bol))
|
||||||
|
:: delete one of our.bol own paths
|
||||||
|
:_ state(synced (~(del by synced) path.act))
|
||||||
|
%- zing
|
||||||
|
:~ (pull-wire [%contacts path.act])
|
||||||
|
[%give %kick ~[[%contacts path.act]] ~]~
|
||||||
|
[%give %fact [/synced]~ %contact-hook-update !>([%initial synced])]~
|
||||||
|
==
|
||||||
|
?. |(=(u.ship src.bol) (team:title our.bol src.bol))
|
||||||
|
:: if neither ship = source or source = us, do nothing
|
||||||
|
[~ state]
|
||||||
|
:: delete a foreign ship's path
|
||||||
|
=/ cards
|
||||||
|
(handle-contact-action path.act our.bol [%remove path.act our.bol])
|
||||||
|
:_ state(synced (~(del by synced) path.act))
|
||||||
|
%- zing
|
||||||
|
:~ (pull-wire [%contacts path.act])
|
||||||
|
[%give %fact [/synced]~ %contact-hook-update !>([%initial synced])]~
|
||||||
|
cards
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ watch-contacts
|
||||||
|
|= pax=path
|
||||||
|
^- (list card)
|
||||||
|
?> ?=(^ pax)
|
||||||
|
?> (~(has by synced) pax)
|
||||||
|
:: scry groups to check if ship is a member
|
||||||
|
=/ =group (need (group-scry pax))
|
||||||
|
?> (~(has in group) src.bol)
|
||||||
|
=/ contacts (need (contacts-scry pax))
|
||||||
|
[%give %fact ~ %contact-update !>([%contacts pax contacts])]~
|
||||||
|
::
|
||||||
|
++ watch-synced
|
||||||
|
|= pax=path
|
||||||
|
^- (list card)
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
[%give %fact ~ %contact-hook-update !>([%initial synced])]~
|
||||||
|
::
|
||||||
|
++ watch-ack
|
||||||
|
|= [wir=wire saw=(unit tang)]
|
||||||
|
^- (quip card _state)
|
||||||
|
?~ saw
|
||||||
|
[~ state]
|
||||||
|
?> ?=(^ wir)
|
||||||
|
[~ state(synced (~(del by synced) t.wir))]
|
||||||
|
::
|
||||||
|
++ kick
|
||||||
|
|= wir=wire
|
||||||
|
^- (list card)
|
||||||
|
?+ wir !!
|
||||||
|
[%inv ~]
|
||||||
|
[%pass /inv %agent [our.bol %invite-store] %watch /invitatory/contacts]~
|
||||||
|
::
|
||||||
|
[%group ~]
|
||||||
|
[%pass /group %agent [our.bol %group-store] %watch /updates]~
|
||||||
|
::
|
||||||
|
[%contacts @ *]
|
||||||
|
?. (~(has by synced) t.wir) ~
|
||||||
|
=/ =ship (~(got by synced) t.wir)
|
||||||
|
?: =(ship our.bol)
|
||||||
|
[%pass wir %agent [our.bol %contact-store] %watch wir]~
|
||||||
|
[%pass wir %agent [ship %contact-hook] %watch wir]~
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ fact-contact-update
|
||||||
|
|= [wir=wire fact=contact-update]
|
||||||
|
^- (quip card _state)
|
||||||
|
|^
|
||||||
|
?: (team:title our.bol src.bol)
|
||||||
|
(local fact)
|
||||||
|
:_ state
|
||||||
|
(foreign fact)
|
||||||
|
::
|
||||||
|
++ give-fact
|
||||||
|
|= [=path update=contact-update]
|
||||||
|
^- (list card)
|
||||||
|
[%give %fact ~[[%contacts path]] %contact-update !>(update)]~
|
||||||
|
::
|
||||||
|
++ local
|
||||||
|
|= fact=contact-update
|
||||||
|
^- (quip card _state)
|
||||||
|
?+ -.fact [~ state]
|
||||||
|
%add
|
||||||
|
:_ state
|
||||||
|
(give-fact path.fact [%add path.fact ship.fact contact.fact])
|
||||||
|
::
|
||||||
|
%edit
|
||||||
|
:_ state
|
||||||
|
(give-fact path.fact [%edit path.fact ship.fact edit-field.fact])
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
:_ state
|
||||||
|
~[(group-poke [%remove [ship.fact ~ ~] path.fact])]
|
||||||
|
::
|
||||||
|
%delete
|
||||||
|
=. synced (~(del by synced) path.fact)
|
||||||
|
:_ state
|
||||||
|
:~ (group-poke [%unbundle path.fact])
|
||||||
|
(metadata-hook-poke [%remove path.fact])
|
||||||
|
(metadata-poke [%remove path.fact [%contacts path.fact]])
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ foreign
|
||||||
|
|= fact=contact-update
|
||||||
|
^- (list card)
|
||||||
|
?+ -.fact ~
|
||||||
|
%contacts
|
||||||
|
=/ owner (~(got by synced) path.fact)
|
||||||
|
?> =(owner src.bol)
|
||||||
|
=/ have-contacts=(unit contacts)
|
||||||
|
(contacts-scry path.fact)
|
||||||
|
?~ have-contacts
|
||||||
|
:: if we don't have any contacts yet,
|
||||||
|
:: create the entry, and %add every contact
|
||||||
|
::
|
||||||
|
:- (contact-poke [%create path.fact])
|
||||||
|
%+ turn ~(tap by contacts.fact)
|
||||||
|
|= [=ship =contact]
|
||||||
|
(contact-poke [%add path.fact ship contact])
|
||||||
|
:: if we already have some, decide between %add, %remove and recreate
|
||||||
|
:: on a per-contact basis
|
||||||
|
::
|
||||||
|
%- zing
|
||||||
|
%+ turn
|
||||||
|
%~ tap in
|
||||||
|
%- ~(uni in ~(key by contacts.fact))
|
||||||
|
~(key by u.have-contacts)
|
||||||
|
|= =ship
|
||||||
|
^- (list card)
|
||||||
|
=/ have=(unit contact) (~(get by u.have-contacts) ship)
|
||||||
|
=/ want=(unit contact) (~(get by contacts.fact) ship)
|
||||||
|
?~ have
|
||||||
|
[(contact-poke %add path.fact ship (need want))]~
|
||||||
|
?~ want
|
||||||
|
[(contact-poke %remove path.fact ship)]~
|
||||||
|
?: =(u.want u.have) ~
|
||||||
|
::TODO probably want an %all edit-field that resolves to more granular
|
||||||
|
:: updates within the contact-store?
|
||||||
|
:~ (contact-poke %remove path.fact ship)
|
||||||
|
(contact-poke %add path.fact ship u.want)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%add
|
||||||
|
=/ owner (~(get by synced) path.fact)
|
||||||
|
?~ owner ~
|
||||||
|
?> |(=(u.owner src.bol) =(src.bol ship.fact))
|
||||||
|
~[(contact-poke [%add path.fact ship.fact contact.fact])]
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
=/ owner (~(get by synced) path.fact)
|
||||||
|
?~ owner ~
|
||||||
|
?> |(=(u.owner src.bol) =(src.bol ship.fact))
|
||||||
|
%+ welp
|
||||||
|
:~ (group-poke [%remove [ship.fact ~ ~] path.fact])
|
||||||
|
(contact-poke [%remove path.fact ship.fact])
|
||||||
|
==
|
||||||
|
?. =(ship.fact our.bol) ~
|
||||||
|
~[(group-poke [%unbundle path.fact])]
|
||||||
|
::
|
||||||
|
%edit
|
||||||
|
=/ owner (~(got by synced) path.fact)
|
||||||
|
?> |(=(owner src.bol) =(src.bol ship.fact))
|
||||||
|
~[(contact-poke [%edit path.fact ship.fact edit-field.fact])]
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ fact-group-update
|
||||||
|
|= [wir=wire fact=group-update]
|
||||||
|
^- (quip card _state)
|
||||||
|
|^
|
||||||
|
?+ -.fact [~ state]
|
||||||
|
%add (add +.fact)
|
||||||
|
%remove (remove +.fact)
|
||||||
|
%unbundle (unbundle +.fact)
|
||||||
|
==
|
||||||
|
++ add
|
||||||
|
|= [ships=(set ship) =path]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ owner (~(get by synced) path)
|
||||||
|
?~ owner [~ state]
|
||||||
|
?. =(u.owner our.bol) [~ state]
|
||||||
|
:_ state
|
||||||
|
%+ turn ~(tap in (~(del in ships) our.bol))
|
||||||
|
|= =ship
|
||||||
|
(send-invite-poke path ship)
|
||||||
|
::
|
||||||
|
++ unbundle
|
||||||
|
|= =path
|
||||||
|
^- (quip card _state)
|
||||||
|
?. (~(has by synced) path)
|
||||||
|
:_ state
|
||||||
|
[(contact-poke [%delete path])]~
|
||||||
|
:_ state(synced (~(del by synced) path))
|
||||||
|
:~ [%pass [%contacts path] %agent [our.bol %contact-store] %leave ~]
|
||||||
|
[(contact-poke [%delete path])]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ remove
|
||||||
|
|= [members=group =path]
|
||||||
|
^- (quip card _state)
|
||||||
|
:: if pax is synced, remove member from contacts and kick their sub
|
||||||
|
=/ owner=(unit ship) (~(get by synced) path)
|
||||||
|
?~ owner
|
||||||
|
:_ state
|
||||||
|
%+ turn ~(tap in members)
|
||||||
|
|= =ship
|
||||||
|
(contact-poke [%remove path ship])
|
||||||
|
:_ state
|
||||||
|
%- zing
|
||||||
|
%+ turn ~(tap in members)
|
||||||
|
|= =ship
|
||||||
|
:~ [%give %kick ~[[%contacts path]] `ship]
|
||||||
|
?: =(ship our.bol)
|
||||||
|
(contact-poke [%delete path])
|
||||||
|
(contact-poke [%remove path ship])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ send-invite-poke
|
||||||
|
|= [=path =ship]
|
||||||
|
^- card
|
||||||
|
=/ =invite
|
||||||
|
:* our.bol %contact-hook
|
||||||
|
path ship ''
|
||||||
|
==
|
||||||
|
=/ act=invite-action [%invite /contacts (shaf %msg-uid eny.bol) invite]
|
||||||
|
[%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)]
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ fact-invite-update
|
||||||
|
|= [wir=wire fact=invite-update]
|
||||||
|
^- (quip card _state)
|
||||||
|
?+ -.fact [~ state]
|
||||||
|
%accepted
|
||||||
|
=/ changes
|
||||||
|
(poke-hook-action [%add-synced ship.invite.fact path.invite.fact])
|
||||||
|
:-
|
||||||
|
%+ welp
|
||||||
|
:~ (group-hook-poke [%add ship.invite.fact path.invite.fact])
|
||||||
|
(metadata-hook-poke [%add-synced ship.invite.fact path.invite.fact])
|
||||||
|
==
|
||||||
|
-.changes
|
||||||
|
+.changes
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ group-hook-poke
|
||||||
|
|= act=group-hook-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %group-hook] %poke %group-hook-action !>(act)]
|
||||||
|
::
|
||||||
|
++ invite-poke
|
||||||
|
|= act=invite-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)]
|
||||||
|
::
|
||||||
|
++ contact-poke
|
||||||
|
|= act=contact-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]
|
||||||
|
::
|
||||||
|
++ group-poke
|
||||||
|
|= act=group-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %group-store] %poke %group-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-poke
|
||||||
|
|= act=metadata-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %metadata-store] %poke %metadata-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-hook-poke
|
||||||
|
|= act=metadata-hook-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %metadata-hook] %poke %metadata-hook-action !>(act)]
|
||||||
|
::
|
||||||
|
++ contacts-scry
|
||||||
|
|= pax=path
|
||||||
|
^- (unit contacts)
|
||||||
|
=. pax ;:(weld /=contact-store/(scot %da now.bol)/contacts pax /noun)
|
||||||
|
.^((unit contacts) %gx pax)
|
||||||
|
::
|
||||||
|
++ invite-scry
|
||||||
|
|= uid=serial
|
||||||
|
^- (unit invite)
|
||||||
|
=/ pax
|
||||||
|
/=invite-store/(scot %da now.bol)/invite/contacts/(scot %uv uid)/noun
|
||||||
|
.^((unit invite) %gx pax)
|
||||||
|
::
|
||||||
|
++ group-scry
|
||||||
|
|= pax=path
|
||||||
|
^- (unit group)
|
||||||
|
.^((unit group) %gx ;:(weld /=group-store/(scot %da now.bol) pax /noun))
|
||||||
|
::
|
||||||
|
++ pull-wire
|
||||||
|
|= pax=path
|
||||||
|
^- (list card)
|
||||||
|
?> ?=(^ pax)
|
||||||
|
=/ shp (~(get by synced) t.pax)
|
||||||
|
?~ shp ~
|
||||||
|
?: =(u.shp our.bol)
|
||||||
|
[%pass pax %agent [our.bol %contact-store] %leave ~]~
|
||||||
|
[%pass pax %agent [u.shp %contact-hook] %leave ~]~
|
||||||
|
--
|
214
pkg/arvo/app/contact-store.hoon
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
:: contact-store: data store that holds group-based contact data
|
||||||
|
::
|
||||||
|
/+ *contact-json, default-agent, dbug
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
+$ versioned-state
|
||||||
|
$% state-zero
|
||||||
|
state-one
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ rolodex-0 (map path contacts-0)
|
||||||
|
+$ contacts-0 (map ship contact-0)
|
||||||
|
+$ avatar-0 [content-type=@t octs=[p=@ud q=@t]]
|
||||||
|
+$ contact-0
|
||||||
|
$: nickname=@t
|
||||||
|
email=@t
|
||||||
|
phone=@t
|
||||||
|
website=@t
|
||||||
|
notes=@t
|
||||||
|
color=@ux
|
||||||
|
avatar=(unit avatar-0)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ state-zero
|
||||||
|
$: %0
|
||||||
|
rolodex=rolodex-0
|
||||||
|
==
|
||||||
|
+$ state-one
|
||||||
|
$: %1
|
||||||
|
=rolodex
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
=| state-one
|
||||||
|
=* state -
|
||||||
|
%- agent:dbug
|
||||||
|
^- agent:gall
|
||||||
|
=<
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* this .
|
||||||
|
contact-core +>
|
||||||
|
cc ~(. contact-core bowl)
|
||||||
|
def ~(. (default-agent this %|) bowl)
|
||||||
|
::
|
||||||
|
++ on-init on-init:def
|
||||||
|
++ on-save !>(state)
|
||||||
|
++ on-load
|
||||||
|
|= old-vase=vase
|
||||||
|
=/ old !<(versioned-state old-vase)
|
||||||
|
?: ?=(%1 -.old)
|
||||||
|
[~ this(state old)]
|
||||||
|
=/ new-rolodex=^rolodex
|
||||||
|
%- ~(run by rolodex.old)
|
||||||
|
|= cons=contacts-0
|
||||||
|
^- contacts
|
||||||
|
%- ~(run by cons)
|
||||||
|
|= con=contact-0
|
||||||
|
^- contact
|
||||||
|
:* nickname.con
|
||||||
|
email.con
|
||||||
|
phone.con
|
||||||
|
website.con
|
||||||
|
notes.con
|
||||||
|
color.con
|
||||||
|
~
|
||||||
|
==
|
||||||
|
[~ this(state [%1 new-rolodex])]
|
||||||
|
::
|
||||||
|
++ on-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
^- (quip card _this)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
=^ cards state
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
::%json (poke-json:cc !<(json vase))
|
||||||
|
%contact-action (poke-contact-action:cc !<(contact-action vase))
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
|^
|
||||||
|
=/ cards=(list card)
|
||||||
|
?+ path (on-watch:def path)
|
||||||
|
[%all ~] (give %contact-update !>([%rolodex rolodex]))
|
||||||
|
[%updates ~] ~
|
||||||
|
[%contacts @ *]
|
||||||
|
%+ give %contact-update
|
||||||
|
!>([%contacts t.path (~(got by rolodex) t.path)])
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ give
|
||||||
|
|= =cage
|
||||||
|
^- (list card)
|
||||||
|
[%give %fact ~ cage]~
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-peek
|
||||||
|
|= =path
|
||||||
|
^- (unit (unit cage))
|
||||||
|
?+ path (on-peek:def path)
|
||||||
|
[%x %all ~] ``noun+!>(rolodex)
|
||||||
|
[%x %contacts *]
|
||||||
|
?~ t.t.path
|
||||||
|
~
|
||||||
|
``noun+!>((~(get by rolodex) t.t.path))
|
||||||
|
::
|
||||||
|
[%x %contact *]
|
||||||
|
:: /:path/:ship
|
||||||
|
=/ pax `^path`(flop t.t.path)
|
||||||
|
?~ pax ~
|
||||||
|
=/ =ship (slav %p i.pax)
|
||||||
|
?~ t.pax ~
|
||||||
|
=> .(pax `(list @ta)`(flop t.pax))
|
||||||
|
=/ contacts=(unit contacts) (~(get by rolodex) pax)
|
||||||
|
?~ contacts
|
||||||
|
~
|
||||||
|
``noun+!>((~(get by u.contacts) ship))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-agent on-agent:def
|
||||||
|
++ on-arvo on-arvo:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
||||||
|
::
|
||||||
|
::
|
||||||
|
|_ bol=bowl:gall
|
||||||
|
::
|
||||||
|
::++ poke-json
|
||||||
|
:: |= =json
|
||||||
|
:: ^- (quip move _this)
|
||||||
|
:: ?> (team:title our.bol src.bol)
|
||||||
|
:: (poke-contact-action (json-to-action json))
|
||||||
|
::
|
||||||
|
++ poke-contact-action
|
||||||
|
|= action=contact-action
|
||||||
|
^- (quip card _state)
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
?- -.action
|
||||||
|
%create (handle-create +.action)
|
||||||
|
%delete (handle-delete +.action)
|
||||||
|
%add (handle-add +.action)
|
||||||
|
%remove (handle-remove +.action)
|
||||||
|
%edit (handle-edit +.action)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-create
|
||||||
|
|= =path
|
||||||
|
^- (quip card _state)
|
||||||
|
?< (~(has by rolodex) path)
|
||||||
|
:- (send-diff path [%create path])
|
||||||
|
state(rolodex (~(put by rolodex) path *contacts))
|
||||||
|
::
|
||||||
|
++ handle-delete
|
||||||
|
|= =path
|
||||||
|
^- (quip card _state)
|
||||||
|
?. (~(has by rolodex) path) [~ state]
|
||||||
|
:- (send-diff path [%delete path])
|
||||||
|
state(rolodex (~(del by rolodex) path))
|
||||||
|
::
|
||||||
|
++ handle-add
|
||||||
|
|= [=path =ship =contact]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ contacts (~(got by rolodex) path)
|
||||||
|
?< (~(has by contacts) ship)
|
||||||
|
=. contacts (~(put by contacts) ship contact)
|
||||||
|
:- (send-diff path [%add path ship contact])
|
||||||
|
state(rolodex (~(put by rolodex) path contacts))
|
||||||
|
::
|
||||||
|
++ handle-remove
|
||||||
|
|= [=path =ship]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ contacts (~(got by rolodex) path)
|
||||||
|
?. (~(has by contacts) ship) [~ state]
|
||||||
|
=. contacts (~(del by contacts) ship)
|
||||||
|
:- (send-diff path [%remove path ship])
|
||||||
|
state(rolodex (~(put by rolodex) path contacts))
|
||||||
|
::
|
||||||
|
++ handle-edit
|
||||||
|
|= [=path =ship =edit-field]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ contacts (~(got by rolodex) path)
|
||||||
|
=/ contact (~(got by contacts) ship)
|
||||||
|
=. contact (edit-contact contact edit-field)
|
||||||
|
=. contacts (~(put by contacts) ship contact)
|
||||||
|
:- (send-diff path [%edit path ship edit-field])
|
||||||
|
state(rolodex (~(put by rolodex) path contacts))
|
||||||
|
::
|
||||||
|
++ edit-contact
|
||||||
|
|= [con=contact edit=edit-field]
|
||||||
|
^- contact
|
||||||
|
?- -.edit
|
||||||
|
%nickname con(nickname nickname.edit)
|
||||||
|
%email con(email email.edit)
|
||||||
|
%phone con(phone phone.edit)
|
||||||
|
%website con(website website.edit)
|
||||||
|
%notes con(notes notes.edit)
|
||||||
|
%color con(color color.edit)
|
||||||
|
%avatar con(avatar avatar.edit)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ send-diff
|
||||||
|
|= [pax=path upd=contact-update]
|
||||||
|
^- (list card)
|
||||||
|
:~ :*
|
||||||
|
%give %fact
|
||||||
|
~[/all /updates [%contacts pax]]
|
||||||
|
%contact-update !>(upd)
|
||||||
|
== ==
|
||||||
|
--
|
282
pkg/arvo/app/contact-view.hoon
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
:: contact-view: sets up contact JS client and combines commands
|
||||||
|
:: into semantic actions for the UI
|
||||||
|
::
|
||||||
|
/- *group-store,
|
||||||
|
*group-hook,
|
||||||
|
*invite-store,
|
||||||
|
*contact-hook,
|
||||||
|
*metadata-store,
|
||||||
|
*metadata-hook,
|
||||||
|
*permission-group-hook,
|
||||||
|
*permission-hook
|
||||||
|
/+ *server, *contact-json, default-agent, dbug
|
||||||
|
/= index
|
||||||
|
/^ octs
|
||||||
|
/; as-octs:mimes:html
|
||||||
|
/: /===/app/contacts/index
|
||||||
|
/| /html/
|
||||||
|
/~ ~
|
||||||
|
==
|
||||||
|
/= tile-js
|
||||||
|
/^ octs
|
||||||
|
/; as-octs:mimes:html
|
||||||
|
/: /===/app/contacts/js/tile
|
||||||
|
/| /js/
|
||||||
|
/~ ~
|
||||||
|
==
|
||||||
|
/= script
|
||||||
|
/^ octs
|
||||||
|
/; as-octs:mimes:html
|
||||||
|
/: /===/app/contacts/js/index
|
||||||
|
/| /js/
|
||||||
|
/~ ~
|
||||||
|
==
|
||||||
|
/= style
|
||||||
|
/^ octs
|
||||||
|
/; as-octs:mimes:html
|
||||||
|
/: /===/app/contacts/css/index
|
||||||
|
/| /css/
|
||||||
|
/~ ~
|
||||||
|
==
|
||||||
|
/= contact-png
|
||||||
|
/^ (map knot @)
|
||||||
|
/: /===/app/contacts/img /_ /png/
|
||||||
|
::
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
--
|
||||||
|
=* state -
|
||||||
|
::
|
||||||
|
%- agent:dbug
|
||||||
|
^- agent:gall
|
||||||
|
=<
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* this .
|
||||||
|
contact-core +>
|
||||||
|
cc ~(. contact-core bowl)
|
||||||
|
def ~(. (default-agent this %|) bowl)
|
||||||
|
::
|
||||||
|
++ on-init
|
||||||
|
^- (quip card _this)
|
||||||
|
:_ this
|
||||||
|
:~ [%pass /updates %agent [our.bowl %contact-store] %watch /updates]
|
||||||
|
[%pass / %arvo %e %connect [~ /'~groups'] %contact-view]
|
||||||
|
(contact-poke:cc [%create /~/default])
|
||||||
|
(group-poke:cc [%bundle /~/default])
|
||||||
|
(contact-poke:cc [%add /~/default our.bowl *contact])
|
||||||
|
(group-poke:cc [%add [our.bowl ~ ~] /~/default])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-save on-save:def
|
||||||
|
++ on-load on-load:def
|
||||||
|
++ on-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
^- (quip card _this)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
%json [(poke-json:cc !<(json vase)) this]
|
||||||
|
%contact-view-action
|
||||||
|
[(poke-contact-view-action:cc !<(contact-view-action vase)) this]
|
||||||
|
::
|
||||||
|
%handle-http-request
|
||||||
|
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
|
||||||
|
:_ this
|
||||||
|
%+ give-simple-payload:app eyre-id
|
||||||
|
%+ require-authorization:app inbound-request
|
||||||
|
poke-handle-http-request:cc
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
?: ?=([%http-response *] path) [~ this]
|
||||||
|
?. =(/primary path) (on-watch:def path)
|
||||||
|
[[%give %fact ~ %json !>((rolodex-to-json all-scry:cc))]~ this]
|
||||||
|
::
|
||||||
|
++ on-agent
|
||||||
|
|= [=wire =sign:agent:gall]
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ -.sign (on-agent:def wire sign)
|
||||||
|
%kick
|
||||||
|
[[%pass / %agent [our.bol %contact-store] %watch /updates]~ this]
|
||||||
|
::
|
||||||
|
%fact
|
||||||
|
?+ p.cage.sign (on-agent:def wire sign)
|
||||||
|
%contact-update
|
||||||
|
=/ update=json (update-to-json !<(contact-update q.cage.sign))
|
||||||
|
[[%give %fact ~[/primary] %json !>(update)]~ this]
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-arvo
|
||||||
|
|= [=wire =sign-arvo]
|
||||||
|
^- (quip card _this)
|
||||||
|
?. ?=(%bound +<.sign-arvo)
|
||||||
|
(on-arvo:def wire sign-arvo)
|
||||||
|
[~ this]
|
||||||
|
::
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-peek on-peek:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
||||||
|
::
|
||||||
|
|_ bol=bowl:gall
|
||||||
|
++ poke-json
|
||||||
|
|= jon=json
|
||||||
|
^- (list card)
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
(poke-contact-view-action (json-to-view-action jon))
|
||||||
|
::
|
||||||
|
++ poke-contact-view-action
|
||||||
|
|= act=contact-view-action
|
||||||
|
^- (list card)
|
||||||
|
?- -.act
|
||||||
|
%create
|
||||||
|
?> ?=([@ *] path.act)
|
||||||
|
%+ weld
|
||||||
|
:~ (group-poke [%bundle path.act])
|
||||||
|
(contact-poke [%create path.act])
|
||||||
|
(contact-hook-poke [%add-owned path.act])
|
||||||
|
(group-hook-poke [%add our.bol path.act])
|
||||||
|
(group-poke [%add (~(put in ships.act) our.bol) path.act])
|
||||||
|
(perm-group-hook-poke [%associate path.act [[path.act %white] ~ ~]])
|
||||||
|
(permission-hook-poke [%add-owned path.act path.act])
|
||||||
|
==
|
||||||
|
(create-metadata path.act title.act description.act)
|
||||||
|
::
|
||||||
|
%delete
|
||||||
|
%+ weld
|
||||||
|
:~ (contact-hook-poke [%remove path.act])
|
||||||
|
(group-poke [%unbundle path.act])
|
||||||
|
(contact-poke [%delete path.act])
|
||||||
|
==
|
||||||
|
(delete-metadata path.act)
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
:~ (group-poke [%remove [ship.act ~ ~] path.act])
|
||||||
|
(contact-poke [%remove path.act ship.act])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%share
|
||||||
|
:: determine whether to send to our contact-hook or foreign
|
||||||
|
:: send contact-action to contact-hook with %add action
|
||||||
|
[(share-poke recipient.act [%add path.act ship.act contact.act])]~
|
||||||
|
==
|
||||||
|
++ poke-handle-http-request
|
||||||
|
|= =inbound-request:eyre
|
||||||
|
^- simple-payload:http
|
||||||
|
=+ url=(parse-request-line url.request.inbound-request)
|
||||||
|
=/ name=@t
|
||||||
|
=+ back-path=(flop site.url)
|
||||||
|
?~ back-path
|
||||||
|
''
|
||||||
|
i.back-path
|
||||||
|
?+ site.url not-found:gen
|
||||||
|
[%'~groups' %css %index ~] (css-response:gen style)
|
||||||
|
[%'~groups' %js %index ~] (js-response:gen script)
|
||||||
|
[%'~groups' %js %tile ~] (js-response:gen tile-js)
|
||||||
|
[%'~groups' %img *]
|
||||||
|
(png-response:gen (as-octs:mimes:html (~(got by contact-png) `@ta`name)))
|
||||||
|
::
|
||||||
|
:: avatar images
|
||||||
|
::
|
||||||
|
[%'~groups' %avatar @ *]
|
||||||
|
=/ =path (flop t.t.site.url)
|
||||||
|
?~ path not-found:gen
|
||||||
|
=/ contact (contact-scry `^path`(snoc (flop t.path) name))
|
||||||
|
?~ contact not-found:gen
|
||||||
|
?~ avatar.u.contact not-found:gen
|
||||||
|
?- -.u.avatar.u.contact
|
||||||
|
%url [[307 ['location' url.u.avatar.u.contact]~] ~]
|
||||||
|
%octt
|
||||||
|
=/ max-3-days ['cache-control' 'max-age=259200']
|
||||||
|
=/ content-type ['content-type' content-type.u.avatar.u.contact]
|
||||||
|
[[200 [content-type max-3-days ~]] `octs.u.avatar.u.contact]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
[%'~groups' *] (html-response:gen index)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: +utilities
|
||||||
|
::
|
||||||
|
++ contact-poke
|
||||||
|
|= act=contact-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]
|
||||||
|
::
|
||||||
|
++ contact-hook-poke
|
||||||
|
|= act=contact-hook-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %contact-hook] %poke %contact-hook-action !>(act)]
|
||||||
|
::
|
||||||
|
++ share-poke
|
||||||
|
|= [=ship act=contact-action]
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [ship %contact-hook] %poke %contact-action !>(act)]
|
||||||
|
::
|
||||||
|
++ group-poke
|
||||||
|
|= act=group-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %group-store] %poke %group-action !>(act)]
|
||||||
|
::
|
||||||
|
++ group-hook-poke
|
||||||
|
|= act=group-hook-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %group-hook] %poke %group-hook-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-poke
|
||||||
|
|= act=metadata-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %metadata-store] %poke %metadata-action !>(act)]
|
||||||
|
::
|
||||||
|
++ metadata-hook-poke
|
||||||
|
|= act=metadata-hook-action
|
||||||
|
^- card
|
||||||
|
[%pass / %agent [our.bol %metadata-hook] %poke %metadata-hook-action !>(act)]
|
||||||
|
::
|
||||||
|
++ perm-group-hook-poke
|
||||||
|
|= act=permission-group-hook-action
|
||||||
|
^- card
|
||||||
|
:* %pass / %agent [our.bol %permission-group-hook]
|
||||||
|
%poke %permission-group-hook-action !>(act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ permission-hook-poke
|
||||||
|
|= act=permission-hook-action
|
||||||
|
^- card
|
||||||
|
:* %pass / %agent [our.bol %permission-hook]
|
||||||
|
%poke %permission-hook-action !>(act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ create-metadata
|
||||||
|
|= [=path title=@t description=@t]
|
||||||
|
^- (list card)
|
||||||
|
=/ =metadata
|
||||||
|
%* . *metadata
|
||||||
|
title title
|
||||||
|
description description
|
||||||
|
date-created now.bol
|
||||||
|
creator our.bol
|
||||||
|
==
|
||||||
|
:~ (metadata-poke [%add path [%contacts path] metadata])
|
||||||
|
(metadata-hook-poke [%add-owned path])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ delete-metadata
|
||||||
|
|= =path
|
||||||
|
^- (list card)
|
||||||
|
:~ (metadata-poke [%remove path [%contacts path]])
|
||||||
|
(metadata-hook-poke [%remove path])
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ all-scry
|
||||||
|
^- rolodex
|
||||||
|
.^(rolodex %gx /=contact-store/(scot %da now.bol)/all/noun)
|
||||||
|
::
|
||||||
|
++ contact-scry
|
||||||
|
|= pax=path
|
||||||
|
^- (unit contact)
|
||||||
|
=. pax ;:(weld /=contact-store/(scot %da now.bol)/contact pax /noun)
|
||||||
|
.^((unit contact) %gx pax)
|
||||||
|
--
|
1
pkg/arvo/app/contacts/css/index.css
Normal file
BIN
pkg/arvo/app/contacts/img/Chat.png
Normal file
After Width: | Height: | Size: 880 B |
BIN
pkg/arvo/app/contacts/img/ImageUpload.png
Normal file
After Width: | Height: | Size: 865 B |
BIN
pkg/arvo/app/contacts/img/Link.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
pkg/arvo/app/contacts/img/Publish.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
pkg/arvo/app/contacts/img/Spinner.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
pkg/arvo/app/contacts/img/Tile.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
pkg/arvo/app/contacts/img/search.png
Normal file
After Width: | Height: | Size: 951 B |
18
pkg/arvo/app/contacts/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Groups</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||||
|
<link rel="stylesheet" href="/~groups/css/index.css" />
|
||||||
|
<link rel="icon" type="image/png" href="/~launch/img/Favicon.png">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root" />
|
||||||
|
<script src="/~channel/channel.js"></script>
|
||||||
|
<script src="/~modulo/session.js"></script>
|
||||||
|
<script src="/~groups/js/index.js"></script>
|
||||||
|
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
pkg/arvo/app/contacts/js/index.js
Normal file
1
pkg/arvo/app/contacts/js/tile.js
Normal file
@ -1115,7 +1115,7 @@
|
|||||||
=/ fore-pos-diff (sub fore-pos pos)
|
=/ fore-pos-diff (sub fore-pos pos)
|
||||||
=+ vex=((full parse-command-line:he-parser) [1 1] txt)
|
=+ vex=((full parse-command-line:he-parser) [1 1] txt)
|
||||||
?. ?=([* ~ [* @ %ex *] *] vex)
|
?. ?=([* ~ [* @ %ex *] *] vex)
|
||||||
res
|
(he-tab-not-hoon pos :(weld buf (tufa buf.say) "\0a"))
|
||||||
=/ typ p:(slop q:he-hoon-head !>(..dawn))
|
=/ typ p:(slop q:he-hoon-head !>(..dawn))
|
||||||
=/ tl (tab-list-hoon:auto typ p.q.q.p.u.q.vex)
|
=/ tl (tab-list-hoon:auto typ p.q.q.p.u.q.vex)
|
||||||
=/ advance (advance-hoon:auto typ p.q.q.p.u.q.vex)
|
=/ advance (advance-hoon:auto typ p.q.q.p.u.q.vex)
|
||||||
@ -1168,6 +1168,140 @@
|
|||||||
*tank
|
*tank
|
||||||
~(duck easy-print type)
|
~(duck easy-print type)
|
||||||
::
|
::
|
||||||
|
:: Full tab complete for all Dojo sinks and sources is a madmans job.
|
||||||
|
:: Instead, we try to parse limited but common forms we know we can
|
||||||
|
:: autocomplete correctly
|
||||||
|
++ he-tab-not-hoon
|
||||||
|
|= [pos=@ud txt=tape]
|
||||||
|
^+ +>
|
||||||
|
=* res +>
|
||||||
|
|^
|
||||||
|
=/ naked-poke=(unit term)
|
||||||
|
%+ rust txt
|
||||||
|
(full (ifix [col (just `@`10)] ;~(pose sym (easy %$))))
|
||||||
|
?^ naked-poke
|
||||||
|
(complete-naked-poke u.naked-poke)
|
||||||
|
=/ variable=(unit term)
|
||||||
|
%+ rust txt
|
||||||
|
(full (ifix [tis (just `@`10)] ;~(pose sym (easy %$))))
|
||||||
|
?^ variable
|
||||||
|
(complete-variable u.variable)
|
||||||
|
=/ gen-poke-to-app=(unit [term term])
|
||||||
|
%+ rust txt
|
||||||
|
;~ sfix
|
||||||
|
;~ (glue bar)
|
||||||
|
;~(pose ;~(pfix col sym) (easy %$))
|
||||||
|
;~(pose sym (easy %$))
|
||||||
|
==
|
||||||
|
(just `@`10)
|
||||||
|
==
|
||||||
|
?^ gen-poke-to-app
|
||||||
|
(complete-gen-poke-to-app u.gen-poke-to-app)
|
||||||
|
=/ naked-gen=(unit term)
|
||||||
|
%+ rust txt
|
||||||
|
(full (ifix [lus (just `@`10)] ;~(pose sym (easy %$))))
|
||||||
|
?~ naked-gen
|
||||||
|
res
|
||||||
|
(complete-naked-gen u.naked-gen)
|
||||||
|
::
|
||||||
|
++ complete-naked-poke
|
||||||
|
|= app=term
|
||||||
|
=/ pax=path
|
||||||
|
/(scot %p our.hid)/[q.byk.hid]/(scot %da now.hid)/app
|
||||||
|
%+ complete (cat 3 ':' app)
|
||||||
|
%+ murn ~(tap by dir:.^(arch %cy pax))
|
||||||
|
|= [=term ~]
|
||||||
|
^- (unit [^term tank])
|
||||||
|
?. =(app (end 3 (met 3 app) term))
|
||||||
|
~
|
||||||
|
?~ =<(fil .^(arch %cy (weld pax ~[term %hoon])))
|
||||||
|
~
|
||||||
|
`[(cat 3 ':' term) *tank]
|
||||||
|
::
|
||||||
|
++ complete-variable
|
||||||
|
|= variable=term
|
||||||
|
%+ complete variable
|
||||||
|
%+ murn ~(tap by var)
|
||||||
|
|= [name=term =cage]
|
||||||
|
^- (unit [term tank])
|
||||||
|
?. =(variable (end 3 (met 3 variable) name))
|
||||||
|
~
|
||||||
|
`[name (sell q.cage)]
|
||||||
|
::
|
||||||
|
++ complete-gen-poke-to-app
|
||||||
|
|= [app=term gen=term]
|
||||||
|
=. app
|
||||||
|
?:(?=(%$ app) %hood app)
|
||||||
|
%+ complete
|
||||||
|
?: =(%hood app)
|
||||||
|
(cat 3 '|' gen)
|
||||||
|
:((cury cat 3) ':' app '|' gen)
|
||||||
|
=/ pfix=path
|
||||||
|
/(scot %p our.hid)/[q.byk.hid]/(scot %da now.hid)/gen/[app]
|
||||||
|
::
|
||||||
|
%^ tab-generators:auto pfix `app
|
||||||
|
%+ murn
|
||||||
|
~(tap by dir:.^(arch %cy pfix))
|
||||||
|
|= [=term ~]
|
||||||
|
?. =(gen (end 3 (met 3 gen) term))
|
||||||
|
~
|
||||||
|
?~ =<(fil .^(arch %cy (weld pfix ~[term %hoon])))
|
||||||
|
~
|
||||||
|
(some term)
|
||||||
|
::
|
||||||
|
++ complete-naked-gen
|
||||||
|
|= gen=term
|
||||||
|
%+ complete (cat 3 '+' gen)
|
||||||
|
=/ pax=path
|
||||||
|
/(scot %p our.hid)/[q.byk.hid]/(scot %da now.hid)/gen
|
||||||
|
%^ tab-generators:auto pax ~
|
||||||
|
%+ murn
|
||||||
|
~(tap by dir:.^(arch %cy pax))
|
||||||
|
|= [=term ~]
|
||||||
|
?. =(gen (end 3 (met 3 gen) term))
|
||||||
|
~
|
||||||
|
?~ =<(fil .^(arch %cy (weld pax ~[term %hoon])))
|
||||||
|
~
|
||||||
|
(some term)
|
||||||
|
::
|
||||||
|
++ complete
|
||||||
|
|= [completing=term options=(list [term tank])]
|
||||||
|
?~ options
|
||||||
|
res
|
||||||
|
=/ advance
|
||||||
|
(longest-match:auto options)
|
||||||
|
=. pos
|
||||||
|
(dec (lent txt)) :: lock cursor at end
|
||||||
|
=/ back-pos
|
||||||
|
(sub pos (met 3 completing))
|
||||||
|
=/ to-send
|
||||||
|
(trip (rsh 3 (sub pos back-pos) advance))
|
||||||
|
=| fxs=(list sole-effect)
|
||||||
|
::
|
||||||
|
:: Cursor is guaranteed to be at end so we don't worry about the
|
||||||
|
:: backwards case
|
||||||
|
::
|
||||||
|
=. res
|
||||||
|
|- ^+ res
|
||||||
|
?~ to-send
|
||||||
|
(he-diff %mor (flop fxs))
|
||||||
|
=^ lic say (~(transmit sole say) %ins pos `@c`i.to-send)
|
||||||
|
$(to-send t.to-send, fxs [`sole-effect`det+lic fxs], pos +(pos))
|
||||||
|
:: If no options, ring the bell
|
||||||
|
::
|
||||||
|
?: =(~ options)
|
||||||
|
(he-diff %bel ~)
|
||||||
|
:: If only one option, don't print unless the option is already
|
||||||
|
:: typed in.
|
||||||
|
::
|
||||||
|
?: &(?=([* ~] options) !=((met 3 advance) (met 3 completing)))
|
||||||
|
res
|
||||||
|
:: Else, print results
|
||||||
|
::
|
||||||
|
%+ he-diff %tab
|
||||||
|
options
|
||||||
|
--
|
||||||
|
::
|
||||||
++ he-type :: apply input
|
++ he-type :: apply input
|
||||||
|= act/sole-action
|
|= act/sole-action
|
||||||
^+ +>
|
^+ +>
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
:: eth-watcher: ethereum event log collector
|
:: eth-watcher: ethereum event log collector
|
||||||
::
|
::
|
||||||
/- *eth-watcher, spider
|
/- *eth-watcher, spider
|
||||||
/+ default-agent, verb
|
/+ default-agent, verb, dbug
|
||||||
=, ethereum-types
|
=, ethereum-types
|
||||||
=, able:jael
|
=, able:jael
|
||||||
::
|
::
|
||||||
=> |%
|
=> |%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
+$ app-state
|
+$ app-state
|
||||||
$: %3
|
$: %4
|
||||||
dogs=(map path watchdog)
|
dogs=(map path watchdog)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ context [=path dog=watchdog]
|
+$ context [=path dog=watchdog]
|
||||||
+$ watchdog
|
+$ watchdog
|
||||||
$: config
|
$: config
|
||||||
running=(unit =tid:spider)
|
running=(unit [since=@da =tid:spider])
|
||||||
=number:block
|
=number:block
|
||||||
=pending-logs
|
=pending-logs
|
||||||
=history
|
=history
|
||||||
@ -57,6 +57,7 @@
|
|||||||
::
|
::
|
||||||
:: Main
|
:: Main
|
||||||
::
|
::
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=| state=app-state
|
=| state=app-state
|
||||||
%+ verb |
|
%+ verb |
|
||||||
@ -97,7 +98,7 @@
|
|||||||
::
|
::
|
||||||
=? old-state ?=(%2 -.old-state)
|
=? old-state ?=(%2 -.old-state)
|
||||||
%- (slog leaf+"upgrading eth-watcher from %2" ~)
|
%- (slog leaf+"upgrading eth-watcher from %2" ~)
|
||||||
^- app-state
|
^- app-state-3
|
||||||
%= old-state
|
%= old-state
|
||||||
- %3
|
- %3
|
||||||
dogs
|
dogs
|
||||||
@ -108,10 +109,52 @@
|
|||||||
==
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
[cards-1 this(state ?>(?=(%3 -.old-state) old-state))]
|
=? old-state ?=(%3 -.old-state)
|
||||||
|
%- (slog leaf+"upgrading eth-watcher from %3" ~)
|
||||||
|
^- app-state
|
||||||
|
%= old-state
|
||||||
|
- %4
|
||||||
|
dogs
|
||||||
|
%- ~(run by dogs.old-state)
|
||||||
|
|= dog=watchdog-3
|
||||||
|
%= dog
|
||||||
|
-
|
||||||
|
=, -.dog
|
||||||
|
[url eager refresh-rate (mul refresh-rate 6) from contracts topics]
|
||||||
|
::
|
||||||
|
running
|
||||||
|
?~ running.dog ~
|
||||||
|
`[now.bowl u.running.dog]
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
[cards-1 this(state ?>(?=(%4 -.old-state) old-state))]
|
||||||
::
|
::
|
||||||
+$ app-states
|
+$ app-states
|
||||||
$%(app-state-0 app-state-1 app-state-2 app-state)
|
$%(app-state-0 app-state-1 app-state-2 app-state-3 app-state)
|
||||||
|
::
|
||||||
|
+$ app-state-3
|
||||||
|
$: %3
|
||||||
|
dogs=(map path watchdog-3)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ watchdog-3
|
||||||
|
$: config-3
|
||||||
|
running=(unit =tid:spider)
|
||||||
|
=number:block
|
||||||
|
=pending-logs
|
||||||
|
=history
|
||||||
|
blocks=(list block)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ config-3
|
||||||
|
$: url=@ta
|
||||||
|
eager=?
|
||||||
|
refresh-rate=@dr
|
||||||
|
from=number:block
|
||||||
|
contracts=(list address:ethereum)
|
||||||
|
=topics
|
||||||
|
==
|
||||||
::
|
::
|
||||||
+$ app-state-2
|
+$ app-state-2
|
||||||
$: %2
|
$: %2
|
||||||
@ -174,11 +217,11 @@
|
|||||||
?- -.poke
|
?- -.poke
|
||||||
%watch
|
%watch
|
||||||
:: fully restart the watchdog if it doesn't exist yet,
|
:: fully restart the watchdog if it doesn't exist yet,
|
||||||
:: or if the new config changes more than just the url or refresh rate.
|
:: or if result-altering parts of the config changed.
|
||||||
=/ restart=?
|
=/ restart=?
|
||||||
?| !(~(has by dogs.state) path.poke)
|
?| !(~(has by dogs.state) path.poke)
|
||||||
?! .= ->+:(~(got by dogs.state) path.poke)
|
?! .= ->+>+:(~(got by dogs.state) path.poke)
|
||||||
+>.config.poke
|
+>+>.config.poke
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
=/ already (~(has by dogs.state) path.poke)
|
=/ already (~(has by dogs.state) path.poke)
|
||||||
@ -196,7 +239,7 @@
|
|||||||
?=(^ running.u.dog)
|
?=(^ running.u.dog)
|
||||||
==
|
==
|
||||||
~
|
~
|
||||||
=/ =cage [%spider-stop !>([u.running.u.dog &])]
|
=/ =cage [%spider-stop !>([tid.u.running.u.dog &])]
|
||||||
:_ ~
|
:_ ~
|
||||||
`card`[%pass [%starting path.poke] %agent [our.bowl %spider] %poke cage]
|
`card`[%pass [%starting path.poke] %agent [our.bowl %spider] %poke cage]
|
||||||
=/ new-dog
|
=/ new-dog
|
||||||
@ -384,25 +427,34 @@
|
|||||||
::
|
::
|
||||||
%- (slog leaf+"eth-watcher failed; will retry" ~)
|
%- (slog leaf+"eth-watcher failed; will retry" ~)
|
||||||
[[(wait path now.bowl refresh-rate.dog)]~ this]
|
[[(wait path now.bowl refresh-rate.dog)]~ this]
|
||||||
:: start a new thread that checks for updates
|
:: maybe kill a timed-out update thread, maybe start a new one
|
||||||
::
|
::
|
||||||
=^ cards-1=(list card) dog
|
=^ stop-cards=(list card) dog
|
||||||
:: if still running, kill it and restart
|
:: if still running beyond timeout time, kill it
|
||||||
::
|
::
|
||||||
?~ running.dog
|
?. ?& ?=(^ running.dog)
|
||||||
|
::
|
||||||
|
%+ gth now.bowl
|
||||||
|
(add since.u.running.dog timeout-time.dog)
|
||||||
|
==
|
||||||
`dog
|
`dog
|
||||||
::
|
::
|
||||||
%- (slog leaf+"eth-watcher still running; will restart" ~)
|
%- (slog leaf+"eth-watcher {(spud path)} timed out; will restart" ~)
|
||||||
=/ =cage [%spider-stop !>([u.running.dog |])]
|
=/ =cage [%spider-stop !>([tid.u.running.dog |])]
|
||||||
:_ dog(running ~)
|
:_ dog(running ~)
|
||||||
:~ (leave-spider path our.bowl)
|
:~ (leave-spider path our.bowl)
|
||||||
[%pass [%starting path] %agent [our.bowl %spider] %poke cage]
|
[%pass [%starting path] %agent [our.bowl %spider] %poke cage]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
=^ cards-2=(list card) dog
|
=^ start-cards=(list card) dog
|
||||||
|
:: if not (or no longer) running, start a new thread
|
||||||
|
::
|
||||||
|
?^ running.dog
|
||||||
|
`dog
|
||||||
|
::
|
||||||
=/ new-tid=@ta
|
=/ new-tid=@ta
|
||||||
(cat 3 'eth-watcher--' (scot %uv eny.bowl))
|
(cat 3 'eth-watcher--' (scot %uv eny.bowl))
|
||||||
:_ dog(running `new-tid)
|
:_ dog(running `[now.bowl new-tid])
|
||||||
=/ args
|
=/ args
|
||||||
:^ ~ `new-tid %eth-watcher
|
:^ ~ `new-tid %eth-watcher
|
||||||
!>(`watchpup`[- number pending-logs blocks]:dog)
|
!>(`watchpup`[- number pending-logs blocks]:dog)
|
||||||
@ -410,7 +462,7 @@
|
|||||||
(poke-spider path our.bowl %spider-start !>(args))
|
(poke-spider path our.bowl %spider-start !>(args))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
:- [(wait path now.bowl refresh-rate.dog) (weld cards-1 cards-2)]
|
:- [(wait path now.bowl refresh-rate.dog) (weld stop-cards start-cards)]
|
||||||
this(dogs.state (~(put by dogs.state) path dog))
|
this(dogs.state (~(put by dogs.state) path dog))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
::
|
::
|
||||||
++ node-url 'http://eth-mainnet.urbit.org:8545'
|
++ node-url 'http://eth-mainnet.urbit.org:8545'
|
||||||
++ refresh-rate ~h1
|
++ refresh-rate ~h1
|
||||||
|
++ timeout-time ~h2
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
=| state-0
|
=| state-0
|
||||||
@ -207,6 +208,7 @@
|
|||||||
:* node-url
|
:* node-url
|
||||||
|
|
|
|
||||||
refresh-rate
|
refresh-rate
|
||||||
|
timeout-time
|
||||||
public:mainnet-contracts
|
public:mainnet-contracts
|
||||||
~[azimuth delegated-sending]:mainnet-contracts
|
~[azimuth delegated-sending]:mainnet-contracts
|
||||||
~
|
~
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
:_ this :_ ~
|
:_ this :_ ~
|
||||||
[%pass /dill %arvo %d %flog %crud %goad-fail u.error.sign-arvo]
|
[%pass /dill %arvo %d %flog %crud %goad-fail u.error.sign-arvo]
|
||||||
%- (slog leaf+"goad: recompiling all apps" ~)
|
%- (slog leaf+"goad: recompiling all apps" ~)
|
||||||
[(goad |) this]
|
[(goad &) this]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-fail on-fail:def
|
++ on-fail on-fail:def
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
::
|
::
|
||||||
/- *group-store, *group-hook
|
/- *group-store, *group-hook
|
||||||
/+ default-agent, verb, dbug
|
/+ default-agent, verb, dbug
|
||||||
|
~% %group-hook-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
::
|
::
|
||||||
@ -33,8 +34,18 @@
|
|||||||
++ on-init on-init:def
|
++ on-init on-init:def
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old=vase
|
|= =vase
|
||||||
`this(state !<(state-zero old))
|
^- (quip card _this)
|
||||||
|
=/ old !<(state-zero vase)
|
||||||
|
:_ this(state old)
|
||||||
|
%+ murn ~(tap by synced.old)
|
||||||
|
|= [=path =ship]
|
||||||
|
^- (unit card)
|
||||||
|
=/ =wire [(scot %p ship) %group path]
|
||||||
|
=/ =term ?:(=(our.bowl ship) %group-store %group-hook)
|
||||||
|
?: (~(has by wex.bowl) [wire ship term]) ~
|
||||||
|
`[%pass wire %agent [ship term] %watch [%group path]]
|
||||||
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
++ on-peek on-peek:def
|
++ on-peek on-peek:def
|
||||||
++ on-arvo on-arvo:def
|
++ on-arvo on-arvo:def
|
||||||
@ -74,20 +85,26 @@
|
|||||||
?~ p.sign
|
?~ p.sign
|
||||||
[~ this]
|
[~ this]
|
||||||
%- (slog u.p.sign)
|
%- (slog u.p.sign)
|
||||||
?> ?=([@ @ *] wire)
|
?> ?=([@ %group ^] wire)
|
||||||
=/ =ship (slav %p i.wire)
|
=/ =ship (slav %p i.wire)
|
||||||
=. synced.state (~(del by synced.state) t.t.wire)
|
=* group t.t.wire
|
||||||
|
:: only remove from synced if this watch-nack came from the ship we
|
||||||
|
:: thought we were actively syncing from
|
||||||
|
::
|
||||||
|
=? synced.state
|
||||||
|
=(ship (~(gut by synced.state) group ship))
|
||||||
|
(~(del by synced.state) group)
|
||||||
[~ this]
|
[~ this]
|
||||||
::
|
::
|
||||||
%kick
|
%kick
|
||||||
?> ?=([@ @ *] wire)
|
?> ?=([@ %group ^] wire)
|
||||||
=/ =ship (slav %p i.wire)
|
=/ =ship (slav %p i.wire)
|
||||||
?. (~(has by synced.state) wire)
|
=* group t.t.wire
|
||||||
|
?. (~(has by synced.state) group)
|
||||||
[~ this]
|
[~ this]
|
||||||
=/ group-path [%group wire]
|
=* group-path t.wire
|
||||||
=/ group-wire [i.wire group-path]
|
|
||||||
:_ this
|
:_ this
|
||||||
[%pass group-wire %agent [ship %group-hook] %watch group-path]~
|
[%pass wire %agent [ship %group-hook] %watch group-path]~
|
||||||
::
|
::
|
||||||
%fact
|
%fact
|
||||||
?. ?=(%group-update p.cage.sign)
|
?. ?=(%group-update p.cage.sign)
|
||||||
@ -150,10 +167,9 @@
|
|||||||
%remove [(update-subscribers [%group pax.diff] diff) state]
|
%remove [(update-subscribers [%group pax.diff] diff) state]
|
||||||
::
|
::
|
||||||
%unbundle
|
%unbundle
|
||||||
:_ state(synced (~(del by synced.state) pax.diff))
|
=/ ship (~(get by synced.state) pax.diff)
|
||||||
%+ snoc
|
?~ ship [~ state]
|
||||||
(update-subscribers [%group pax.diff] diff)
|
(poke-group-hook-action [%remove pax.diff])
|
||||||
[%give %kick [%group pax.diff]~ ~]
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ handle-foreign
|
++ handle-foreign
|
||||||
@ -162,17 +178,29 @@
|
|||||||
?- -.diff
|
?- -.diff
|
||||||
%keys [~ state]
|
%keys [~ state]
|
||||||
%bundle [~ state]
|
%bundle [~ state]
|
||||||
::
|
|
||||||
%path
|
%path
|
||||||
:_ state
|
:_ state
|
||||||
?~ pax.diff ~
|
?~ pax.diff ~
|
||||||
=/ ship (~(get by synced.state) pax.diff)
|
=/ ship (~(get by synced.state) pax.diff)
|
||||||
?~ ship ~
|
?~ ship ~
|
||||||
?. =(src.bol u.ship) ~
|
?. =(src.bol u.ship) ~
|
||||||
:~ (group-poke pax.diff [%unbundle pax.diff])
|
=/ have-group=(unit group)
|
||||||
(group-poke pax.diff [%bundle pax.diff])
|
(group-scry pax.diff)
|
||||||
(group-poke pax.diff [%add members.diff pax.diff])
|
?~ have-group
|
||||||
==
|
:: if we don't have the group yet, create it
|
||||||
|
::
|
||||||
|
:~ (group-poke pax.diff [%bundle pax.diff])
|
||||||
|
(group-poke pax.diff [%add members.diff pax.diff])
|
||||||
|
==
|
||||||
|
:: if we already have the group, calculate and apply the diff
|
||||||
|
::
|
||||||
|
=/ added=group (~(dif in members.diff) u.have-group)
|
||||||
|
=/ removed=group (~(dif in u.have-group) members.diff)
|
||||||
|
%+ weld
|
||||||
|
?~ added ~
|
||||||
|
[(group-poke pax.diff [%add added pax.diff])]~
|
||||||
|
?~ removed ~
|
||||||
|
[(group-poke pax.diff [%remove removed pax.diff])]~
|
||||||
::
|
::
|
||||||
%add
|
%add
|
||||||
:_ state
|
:_ state
|
||||||
@ -183,23 +211,26 @@
|
|||||||
[(group-poke pax.diff diff)]~
|
[(group-poke pax.diff diff)]~
|
||||||
::
|
::
|
||||||
%remove
|
%remove
|
||||||
:_ state
|
?~ pax.diff [~ state]
|
||||||
?~ pax.diff ~
|
|
||||||
=/ ship (~(get by synced.state) pax.diff)
|
=/ ship (~(get by synced.state) pax.diff)
|
||||||
?~ ship ~
|
?~ ship [~ state]
|
||||||
?. =(src.bol u.ship) ~
|
?. =(src.bol u.ship) [~ state]
|
||||||
[(group-poke pax.diff diff)]~
|
?. (~(has in members.diff) our.bol)
|
||||||
|
:_ state
|
||||||
|
[(group-poke pax.diff diff)]~
|
||||||
|
=/ changes (poke-group-hook-action [%remove pax.diff])
|
||||||
|
:_ +.changes
|
||||||
|
%+ welp -.changes
|
||||||
|
:~ (group-poke pax.diff diff)
|
||||||
|
(group-poke pax.diff [%unbundle pax.diff])
|
||||||
|
==
|
||||||
::
|
::
|
||||||
%unbundle
|
%unbundle
|
||||||
?~ pax.diff
|
?~ pax.diff [~ state]
|
||||||
[~ state]
|
|
||||||
=/ ship (~(get by synced.state) pax.diff)
|
=/ ship (~(get by synced.state) pax.diff)
|
||||||
?~ ship
|
?~ ship [~ state]
|
||||||
[~ state]
|
?. =(src.bol u.ship) [~ state]
|
||||||
?. =(src.bol u.ship)
|
(poke-group-hook-action [%remove pax.diff])
|
||||||
[~ state]
|
|
||||||
:_ state(synced (~(del by synced.state) pax.diff))
|
|
||||||
[(group-poke pax.diff diff)]~
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ group-poke
|
++ group-poke
|
||||||
@ -226,5 +257,4 @@
|
|||||||
?: =(u.shp our.bol)
|
?: =(u.shp our.bol)
|
||||||
[%pass wir %agent [our.bol %group-store] %leave ~]~
|
[%pass wir %agent [our.bol %group-store] %leave ~]~
|
||||||
[%pass wir %agent [u.shp %group-hook] %leave ~]~
|
[%pass wir %agent [u.shp %group-hook] %leave ~]~
|
||||||
::
|
|
||||||
--
|
--
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
=/ cards=(list card)
|
=/ cards=(list card)
|
||||||
?+ path (on-watch:def path)
|
?+ path (on-watch:def path)
|
||||||
[%all ~] (give %group-initial !>(groups))
|
[%all ~] (give %group-initial !>(groups))
|
||||||
|
[%updates ~] ~
|
||||||
[%keys ~] (give %group-update !>([%keys ~(key by groups)]))
|
[%keys ~] (give %group-update !>([%keys ~(key by groups)]))
|
||||||
[%group *]
|
[%group *]
|
||||||
(give %group-update !>([%path (~(got by groups) t.path) t.path]))
|
(give %group-update !>([%path (~(got by groups) t.path) t.path]))
|
||||||
@ -158,6 +159,7 @@
|
|||||||
^- (list card)
|
^- (list card)
|
||||||
%- zing
|
%- zing
|
||||||
:~ (update-subscribers /all act)
|
:~ (update-subscribers /all act)
|
||||||
|
(update-subscribers /updates act)
|
||||||
(update-subscribers [%group pax] act)
|
(update-subscribers [%group pax] act)
|
||||||
?. |(=(%bundle -.act) =(%unbundle -.act))
|
?. |(=(%bundle -.act) =(%unbundle -.act))
|
||||||
~
|
~
|
||||||
|
@ -43,9 +43,9 @@
|
|||||||
!:
|
!:
|
||||||
=> |% ::
|
=> |% ::
|
||||||
++ hood-old :: unified old-state
|
++ hood-old :: unified old-state
|
||||||
{?($1 $2) lac/(map @tas hood-part-old)} ::
|
{?($1 $2 $3 $4) lac/(map @tas hood-part-old)} ::
|
||||||
++ hood-1 :: unified state
|
++ hood-1 :: unified state
|
||||||
{$2 lac/(map @tas hood-part)} ::
|
{$4 lac/(map @tas hood-part)} ::
|
||||||
++ hood-good :: extract specific
|
++ hood-good :: extract specific
|
||||||
=+ hed=$:hood-head
|
=+ hed=$:hood-head
|
||||||
|@ ++ $
|
|@ ++ $
|
||||||
@ -140,16 +140,19 @@
|
|||||||
`..on-init
|
`..on-init
|
||||||
::
|
::
|
||||||
++ on-save
|
++ on-save
|
||||||
!>([%2 lac])
|
!>([%4 lac])
|
||||||
::
|
::
|
||||||
++ on-load
|
++ on-load
|
||||||
|= =old-state=vase
|
|= =old-state=vase
|
||||||
=/ old-state !<(hood-old old-state-vase)
|
=/ old-state !<(hood-old old-state-vase)
|
||||||
=^ cards lac
|
=^ cards lac
|
||||||
=. lac lac.old-state
|
=. lac lac.old-state
|
||||||
?. ?=(%1 -.old-state)
|
?- -.old-state
|
||||||
`lac
|
%1 ((wrap on-load):from-drum:(help hid) %1)
|
||||||
((wrap on-load):from-drum:(help hid) %1)
|
%2 ((wrap on-load):from-drum:(help hid) %2)
|
||||||
|
%3 ((wrap on-load):from-drum:(help hid) %3)
|
||||||
|
%4 `lac
|
||||||
|
==
|
||||||
[cards ..on-init]
|
[cards ..on-init]
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
:: can be poked by the host team to send an invite out to someone.
|
:: can be poked by the host team to send an invite out to someone.
|
||||||
:: can be poked by foreign ships to send an invite to us.
|
:: can be poked by foreign ships to send an invite to us.
|
||||||
::
|
::
|
||||||
/+ *invite-json, default-agent, verb
|
/+ *invite-json, default-agent, verb, dbug
|
||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ state-0 [%0 ~]
|
+$ state-0 [%0 ~]
|
||||||
@ -16,6 +16,7 @@
|
|||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
%+ verb |
|
%+ verb |
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
@ -49,12 +50,10 @@
|
|||||||
%invite-action
|
%invite-action
|
||||||
=/ act=invite-action !<(invite-action vase)
|
=/ act=invite-action !<(invite-action vase)
|
||||||
?. ?=(%invite -.act) ~
|
?. ?=(%invite -.act) ~
|
||||||
:: if the sender is us,
|
|
||||||
::
|
|
||||||
?: (team:title our.bowl src.bowl)
|
?: (team:title our.bowl src.bowl)
|
||||||
:: outgoing. we must be inviting another ship. send them the invite.
|
:: outgoing. we must be inviting another ship. send them the invite.
|
||||||
::
|
::
|
||||||
?> !(team:title our.bowl recipient.invite.act)
|
?< (team:title our.bowl recipient.invite.act)
|
||||||
[(invite-hook-poke:do recipient.invite.act act)]~
|
[(invite-hook-poke:do recipient.invite.act act)]~
|
||||||
:: else incoming. ensure invitatory exists and invite is not a duplicate.
|
:: else incoming. ensure invitatory exists and invite is not a duplicate.
|
||||||
::
|
::
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/+ *invite-json, default-agent
|
/+ *invite-json, default-agent, dbug
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
::
|
::
|
||||||
@ -14,6 +14,7 @@
|
|||||||
::
|
::
|
||||||
=| state-zero
|
=| state-zero
|
||||||
=* state -
|
=* state -
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
::
|
::
|
||||||
::TODO could maybe use /lib/proxy-hook, be renamed invite-proxy-hook
|
::TODO could maybe use /lib/proxy-hook, be renamed invite-proxy-hook
|
||||||
::
|
::
|
||||||
/+ *invite-json, default-agent
|
/+ *invite-json, default-agent, dbug
|
||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
@ -19,6 +19,8 @@
|
|||||||
^- card
|
^- card
|
||||||
[%pass /store %agent [our %invite-store] %watch /updates]
|
[%pass /store %agent [our %invite-store] %watch /updates]
|
||||||
--
|
--
|
||||||
|
::
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/- launch
|
/- launch
|
||||||
/+ *server, default-agent
|
/+ *server, default-agent, dbug
|
||||||
::
|
::
|
||||||
/= index
|
/= index
|
||||||
/^ $-(marl manx)
|
/^ $-([json marl] manx)
|
||||||
/: /===/app/launch/index /!noun/
|
/: /===/app/launch/index /!noun/
|
||||||
/= script
|
/= script
|
||||||
/^ octs
|
/^ octs
|
||||||
@ -11,6 +11,13 @@
|
|||||||
/| /js/
|
/| /js/
|
||||||
/~ ~
|
/~ ~
|
||||||
==
|
==
|
||||||
|
/= channel-js
|
||||||
|
/^ octs
|
||||||
|
/; as-octs:mimes:html
|
||||||
|
/: /===/app/launch/js/channel
|
||||||
|
/| /js/
|
||||||
|
/~ ~
|
||||||
|
==
|
||||||
/= style
|
/= style
|
||||||
/^ octs
|
/^ octs
|
||||||
/; as-octs:mimes:html
|
/; as-octs:mimes:html
|
||||||
@ -24,53 +31,108 @@
|
|||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% state-zero
|
$% [%0 state-zero]
|
||||||
|
[%1 state-two]
|
||||||
|
[%2 state-two]
|
||||||
|
[%3 state-two]
|
||||||
==
|
==
|
||||||
+$ state-zero
|
+$ state-zero
|
||||||
$: %0
|
$: tiles=(set tile:launch)
|
||||||
tiles=(set tile:launch)
|
|
||||||
data=tile-data:launch
|
data=tile-data:launch
|
||||||
path-to-tile=(map path @tas)
|
path-to-tile=(map path @tas)
|
||||||
==
|
==
|
||||||
|
+$ state-two
|
||||||
|
$: tiles=(set tile:launch)
|
||||||
|
data=tile-data:launch
|
||||||
|
path-to-tile=(map path @tas)
|
||||||
|
first-time=?
|
||||||
|
==
|
||||||
::
|
::
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
|
++ launch-who
|
||||||
|
|= =desk
|
||||||
|
[%pass /who %arvo %e %serve [~ /who] desk /gen/who/hoon ~]
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
=| state-zero
|
=| [%3 state-two]
|
||||||
=* state -
|
=* state -
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
|_ bol=bowl:gall
|
|_ bol=bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
def ~(. (default-agent this %|) bol)
|
def ~(. (default-agent this %|) bol)
|
||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
:_ this
|
:_ this(state *[%3 state-two])
|
||||||
[%pass / %arvo %e %connect [~ /] %launch]~
|
:~ (launch-who q.byk.bol)
|
||||||
|
[%pass / %arvo %e %connect [~ /] %launch]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
::
|
::
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old=vase
|
|= old=vase
|
||||||
`this(state !<(state-zero old))
|
^- (quip card _this)
|
||||||
|
=/ old-state !<(versioned-state old)
|
||||||
|
=| cards=(list card)
|
||||||
|
|-
|
||||||
|
?- -.old-state
|
||||||
|
%0
|
||||||
|
$(old-state [%1 tiles data path-to-tile %.n]:old-state)
|
||||||
|
::
|
||||||
|
%1
|
||||||
|
=/ new-state=state-two
|
||||||
|
=, old-state
|
||||||
|
:* (~(del in tiles) [%contact-view /primary])
|
||||||
|
(~(del by data) %contact-view)
|
||||||
|
(~(del by path-to-tile) /primary)
|
||||||
|
first-time
|
||||||
|
==
|
||||||
|
$(old-state [%2 new-state])
|
||||||
|
::
|
||||||
|
%2
|
||||||
|
$(old-state [%3 +.old-state], cards [(launch-who q.byk.bol) cards])
|
||||||
|
::
|
||||||
|
%3
|
||||||
|
[(flop cards) this(state old-state)]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|= [mar=mark vas=vase]
|
|= [mar=mark vas=vase]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?+ mar (on-poke:def mar vas)
|
?+ mar (on-poke:def mar vas)
|
||||||
|
%json
|
||||||
|
?> (team:title our.bol src.bol)
|
||||||
|
=/ jon !<(json vas)
|
||||||
|
:- ~
|
||||||
|
?. =(jon [%s 'disable welcome message'])
|
||||||
|
this
|
||||||
|
this(first-time %.n)
|
||||||
::
|
::
|
||||||
%launch-action
|
%launch-action
|
||||||
=/ act !<(action:launch vas)
|
=/ act !<(action:launch vas)
|
||||||
=/ beforedata (~(get by data) name.act)
|
?- -.act
|
||||||
=/ newdata
|
%add
|
||||||
?~ beforedata
|
=/ beforedata (~(get by data) name.act)
|
||||||
(~(put by data) name.act [*json url.act])
|
=/ newdata
|
||||||
(~(put by data) name.act [jon.u.beforedata url.act])
|
?~ beforedata
|
||||||
=/ new-tile `tile:launch`[`@tas`name.act `path`subscribe.act]
|
(~(put by data) name.act [*json url.act])
|
||||||
:- [%pass subscribe.act %agent [our.bol name.act] %watch subscribe.act]~
|
(~(put by data) name.act [jon.u.beforedata url.act])
|
||||||
%= this
|
=/ new-tile `tile:launch`[`@tas`name.act `path`subscribe.act]
|
||||||
tiles (~(put in tiles) new-tile)
|
:- [%pass subscribe.act %agent [our.bol name.act] %watch subscribe.act]~
|
||||||
data newdata
|
%= this
|
||||||
path-to-tile (~(put by path-to-tile) subscribe.act name.act)
|
tiles (~(put in tiles) new-tile)
|
||||||
|
data newdata
|
||||||
|
path-to-tile (~(put by path-to-tile) subscribe.act name.act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
:- [%pass subscribe.act %agent [our.bol name.act] %leave ~]~
|
||||||
|
%= this
|
||||||
|
tiles (~(del in tiles) [name.act subscribe.act])
|
||||||
|
data (~(del by data) name.act)
|
||||||
|
path-to-tile (~(del by path-to-tile) subscribe.act)
|
||||||
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%handle-http-request
|
%handle-http-request
|
||||||
@ -89,9 +151,10 @@
|
|||||||
?+ site.request-line
|
?+ site.request-line
|
||||||
not-found:gen
|
not-found:gen
|
||||||
::
|
::
|
||||||
~
|
[~ ~]
|
||||||
=/ hym=manx
|
=/ hym=manx
|
||||||
%- index
|
%+ index
|
||||||
|
[%b first-time]
|
||||||
^- marl
|
^- marl
|
||||||
%+ turn ~(tap by data)
|
%+ turn ~(tap by data)
|
||||||
|= [key=@tas [jon=json url=@t]]
|
|= [key=@tas [jon=json url=@t]]
|
||||||
@ -119,6 +182,9 @@
|
|||||||
"window.urb = new Channel();"
|
"window.urb = new Channel();"
|
||||||
==
|
==
|
||||||
(js-response:gen session-js)
|
(js-response:gen session-js)
|
||||||
|
::
|
||||||
|
[%'~channel' %channel ~]
|
||||||
|
(js-response:gen channel-js)
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
BIN
pkg/arvo/app/launch/img/Chevron.png
Normal file
After Width: | Height: | Size: 453 B |
@ -1,4 +1,4 @@
|
|||||||
|= scripts=marl
|
|= [startup=json scripts=marl]
|
||||||
;html
|
;html
|
||||||
;head
|
;head
|
||||||
;title: Home
|
;title: Home
|
||||||
@ -11,9 +11,10 @@
|
|||||||
==
|
==
|
||||||
;body
|
;body
|
||||||
;div#root;
|
;div#root;
|
||||||
;script@"/~/channel/channel.js";
|
;script@"/~channel/channel.js";
|
||||||
;script@"/~modulo/session.js";
|
;script@"/~modulo/session.js";
|
||||||
;* scripts
|
;* scripts
|
||||||
;script@"/~launch/js/index.js";
|
;script@"/~launch/js/index.js";
|
||||||
|
;script: window.startupMessage = {(en-json:html startup)}
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
|
231
pkg/arvo/app/launch/js/channel.js
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
class Channel {
|
||||||
|
constructor() {
|
||||||
|
this.init();
|
||||||
|
this.deleteOnUnload();
|
||||||
|
|
||||||
|
// a way to handle channel errors
|
||||||
|
//
|
||||||
|
//
|
||||||
|
this.onChannelError = (err) => {
|
||||||
|
console.error('event source error: ', err);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// unique identifier: current time and random number
|
||||||
|
//
|
||||||
|
this.uid =
|
||||||
|
new Date().getTime().toString() +
|
||||||
|
"-" +
|
||||||
|
Math.random().toString(16).slice(-6);
|
||||||
|
|
||||||
|
this.requestId = 1;
|
||||||
|
|
||||||
|
// the currently connected EventSource
|
||||||
|
//
|
||||||
|
this.eventSource = null;
|
||||||
|
|
||||||
|
// the id of the last EventSource event we received
|
||||||
|
//
|
||||||
|
this.lastEventId = 0;
|
||||||
|
|
||||||
|
// this last event id acknowledgment sent to the server
|
||||||
|
//
|
||||||
|
this.lastAcknowledgedEventId = 0;
|
||||||
|
|
||||||
|
// a registry of requestId to successFunc/failureFunc
|
||||||
|
//
|
||||||
|
// These functions are registered during a +poke and are executed
|
||||||
|
// in the onServerEvent()/onServerError() callbacks. Only one of
|
||||||
|
// the functions will be called, and the outstanding poke will be
|
||||||
|
// removed after calling the success or failure function.
|
||||||
|
//
|
||||||
|
|
||||||
|
this.outstandingPokes = new Map();
|
||||||
|
|
||||||
|
// a registry of requestId to subscription functions.
|
||||||
|
//
|
||||||
|
// These functions are registered during a +subscribe and are
|
||||||
|
// executed in the onServerEvent()/onServerError() callbacks. The
|
||||||
|
// event function will be called whenever a new piece of data on this
|
||||||
|
// subscription is available, which may be 0, 1, or many times. The
|
||||||
|
// disconnect function may be called exactly once.
|
||||||
|
//
|
||||||
|
this.outstandingSubscriptions = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnChannelError(onError = (err) => {}) {
|
||||||
|
this.onChannelError = onError;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteOnUnload() {
|
||||||
|
window.addEventListener("unload", (event) => {
|
||||||
|
this.delete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// sends a poke to an app on an urbit ship
|
||||||
|
//
|
||||||
|
poke(ship, app, mark, json, successFunc, failureFunc) {
|
||||||
|
let id = this.nextId();
|
||||||
|
this.outstandingPokes.set(
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
success: successFunc,
|
||||||
|
fail: failureFunc
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sendJSONToChannel({
|
||||||
|
id,
|
||||||
|
action: "poke",
|
||||||
|
ship,
|
||||||
|
app,
|
||||||
|
mark,
|
||||||
|
json
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribes to a path on an specific app and ship.
|
||||||
|
//
|
||||||
|
// Returns a subscription id, which is the same as the same internal id
|
||||||
|
// passed to your Urbit.
|
||||||
|
subscribe(
|
||||||
|
ship,
|
||||||
|
app,
|
||||||
|
path,
|
||||||
|
connectionErrFunc = () => {},
|
||||||
|
eventFunc = () => {},
|
||||||
|
quitFunc = () => {}) {
|
||||||
|
let id = this.nextId();
|
||||||
|
this.outstandingSubscriptions.set(
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
err: connectionErrFunc,
|
||||||
|
event: eventFunc,
|
||||||
|
quit: quitFunc
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sendJSONToChannel({
|
||||||
|
id,
|
||||||
|
action: "subscribe",
|
||||||
|
ship,
|
||||||
|
app,
|
||||||
|
path
|
||||||
|
});
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quit the channel
|
||||||
|
//
|
||||||
|
delete() {
|
||||||
|
let id = this.nextId();
|
||||||
|
navigator.sendBeacon(this.channelURL(), JSON.stringify([{
|
||||||
|
id,
|
||||||
|
action: "delete"
|
||||||
|
}]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsubscribe to a specific subscription
|
||||||
|
//
|
||||||
|
unsubscribe(subscription) {
|
||||||
|
let id = this.nextId();
|
||||||
|
this.sendJSONToChannel({
|
||||||
|
id,
|
||||||
|
action: "unsubscribe",
|
||||||
|
subscription
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// sends a JSON command command to the server.
|
||||||
|
//
|
||||||
|
sendJSONToChannel(j) {
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
req.open("PUT", this.channelURL());
|
||||||
|
req.setRequestHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
if (this.lastEventId == this.lastAcknowledgedEventId) {
|
||||||
|
let x = JSON.stringify([j]);
|
||||||
|
req.send(x);
|
||||||
|
} else {
|
||||||
|
// we add an acknowledgment to clear the server side queue
|
||||||
|
//
|
||||||
|
// The server side puts messages it sends us in a queue until we
|
||||||
|
// acknowledge that we received it.
|
||||||
|
//
|
||||||
|
let x = JSON.stringify(
|
||||||
|
[{action: "ack", "event-id": parseInt(this.lastEventId)}, j]
|
||||||
|
);
|
||||||
|
req.send(x);
|
||||||
|
|
||||||
|
this.lastEventId = this.lastAcknowledgedEventId;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connectIfDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
// connects to the EventSource if we are not currently connected
|
||||||
|
//
|
||||||
|
connectIfDisconnected() {
|
||||||
|
if (this.eventSource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventSource = new EventSource(this.channelURL(), {withCredentials:true});
|
||||||
|
this.eventSource.onmessage = e => {
|
||||||
|
this.lastEventId = e.lastEventId;
|
||||||
|
|
||||||
|
let obj = JSON.parse(e.data);
|
||||||
|
let pokeFuncs = this.outstandingPokes.get(obj.id);
|
||||||
|
let subFuncs = this.outstandingSubscriptions.get(obj.id);
|
||||||
|
|
||||||
|
if (obj.response == "poke" && !!pokeFuncs) {
|
||||||
|
let funcs = pokeFuncs;
|
||||||
|
if (obj.hasOwnProperty("ok")) {
|
||||||
|
funcs["success"]();
|
||||||
|
} else if (obj.hasOwnProperty("err")) {
|
||||||
|
funcs["fail"](obj.err);
|
||||||
|
} else {
|
||||||
|
console.error("Invalid poke response: ", obj);
|
||||||
|
}
|
||||||
|
this.outstandingPokes.delete(obj.id);
|
||||||
|
|
||||||
|
} else if (obj.response == "subscribe" ||
|
||||||
|
(obj.response == "poke" && !!subFuncs)) {
|
||||||
|
let funcs = subFuncs;
|
||||||
|
// on a response to a subscribe, we only notify the caller on err
|
||||||
|
//
|
||||||
|
if (obj.hasOwnProperty("err")) {
|
||||||
|
funcs["err"](obj.err);
|
||||||
|
this.outstandingSubscriptions.delete(obj.id);
|
||||||
|
}
|
||||||
|
} else if (obj.response == "diff") {
|
||||||
|
let funcs = subFuncs;
|
||||||
|
funcs["event"](obj.json);
|
||||||
|
} else if (obj.response == "quit") {
|
||||||
|
let funcs = subFuncs;
|
||||||
|
funcs["quit"](obj);
|
||||||
|
this.outstandingSubscriptions.delete(obj.id);
|
||||||
|
} else {
|
||||||
|
console.log("Unrecognized response: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventSource.onerror = e => {
|
||||||
|
this.delete();
|
||||||
|
this.init();
|
||||||
|
this.onChannelError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channelURL() {
|
||||||
|
return "/~/channel/" + this.uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextId() {
|
||||||
|
return this.requestId++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,30 +1,70 @@
|
|||||||
:: link-listen-hook: get your friends' bookmarks
|
:: link-listen-hook: get your friends' bookmarks
|
||||||
::
|
::
|
||||||
:: on-init, subscribes to all groups on this ship.
|
:: keeps track of a listening=(set app-path). users can manually add to and
|
||||||
:: for every ship in a group, we subscribe to their link's local-pages
|
:: remove from this set.
|
||||||
:: at the group path (through link-proxy-hook),
|
|
||||||
:: and forwards all entries into our link as submissions.
|
|
||||||
::
|
::
|
||||||
/- *link, group-store
|
:: for all ships in groups associated with those resources, we subscribe to
|
||||||
/+ default-agent, verb
|
:: their link's local-pages and annotations at the resource path (through
|
||||||
|
:: link-proxy-hook), and forward all entries into our link-store as
|
||||||
|
:: submissions and comments.
|
||||||
::
|
::
|
||||||
|
:: if a subscription to a target fails, we assume it's because their
|
||||||
|
:: metadata+groups definition hasn't been updated to include us yet.
|
||||||
|
:: we retry with exponential backoff, maxing out at one hour timeouts.
|
||||||
|
:: to expede this process, we prod other potential listeners when we add
|
||||||
|
:: them to our metadata+groups definition.
|
||||||
|
::
|
||||||
|
/- link-listen-hook, *metadata-store, *link, group-store
|
||||||
|
/+ mdl=metadata, default-agent, verb, dbug
|
||||||
|
::
|
||||||
|
~% %link-listen-hook-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ state-0
|
+$ versioned-state
|
||||||
$: %0
|
$% [%0 state-0]
|
||||||
~
|
[%1 state-1]
|
||||||
::NOTE this means we could get away with just producing cards everywhere,
|
[%2 state-2]
|
||||||
:: never producing new state outside of the agent interface core.
|
|
||||||
:: we opt to keep ^-(quip card _state) in place for most logic arms
|
|
||||||
:: because it doesn't cost much, results in unsurprising code, and
|
|
||||||
:: makes adding any state in the future easier.
|
|
||||||
==
|
==
|
||||||
|
+$ state-2 state-1
|
||||||
|
+$ state-1
|
||||||
|
$: listening=(set app-path)
|
||||||
|
state-0
|
||||||
|
==
|
||||||
|
+$ state-0
|
||||||
|
$: retry-timers=(map target @dr)
|
||||||
|
:: reasoning: the resources we're subscribed to,
|
||||||
|
:: and the groups that cause that.
|
||||||
|
::
|
||||||
|
:: we don't strictly need to track this in state, but doing so heavily
|
||||||
|
:: simplifies logic and reduces the amount of big scries we do.
|
||||||
|
:: this also gives us the option to check & restore subscriptions,
|
||||||
|
:: should we ever need that.
|
||||||
|
::
|
||||||
|
reasoning=(jug [ship app-path] group-path)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ what-target ?(%local-pages %annotations)
|
||||||
|
+$ target
|
||||||
|
$: what=what-target
|
||||||
|
who=ship
|
||||||
|
where=path
|
||||||
|
==
|
||||||
|
++ wire-to-target
|
||||||
|
|= =wire
|
||||||
|
^- target
|
||||||
|
?> ?=([what-target @ ^] wire)
|
||||||
|
[i.wire (slav %p i.t.wire) t.t.wire]
|
||||||
|
++ target-to-wire
|
||||||
|
|= target
|
||||||
|
^- wire
|
||||||
|
[what (scot %p who) where]
|
||||||
::
|
::
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
=| state-0
|
=| [%2 state-2]
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
|
%- agent:dbug
|
||||||
%+ verb |
|
%+ verb |
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
@ -36,53 +76,244 @@
|
|||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
:_ this
|
:_ this
|
||||||
[watch-groups:do]~
|
~[watch-metadata:do watch-groups:do]
|
||||||
::
|
::
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
++ on-load
|
++ on-load
|
||||||
|= old=vase
|
|= =vase
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
[~ this(state !<(state-0 old))]
|
=/ old=versioned-state
|
||||||
|
!<(versioned-state vase)
|
||||||
|
|-
|
||||||
|
?- -.old
|
||||||
|
%2 [~ this(state old)]
|
||||||
|
::
|
||||||
|
%1
|
||||||
|
:: the upgrade from 0 left out local-only collections.
|
||||||
|
:: here, we pull those back in.
|
||||||
|
::
|
||||||
|
=. state [%2 +.old]
|
||||||
|
=. listening.state
|
||||||
|
(~(run in ~(key by reasoning.old)) tail)
|
||||||
|
=/ resources=(list [=group-path =app-path])
|
||||||
|
%~ tap in
|
||||||
|
%. %link
|
||||||
|
%~ get ju
|
||||||
|
.^ (jug app-name [group-path app-path])
|
||||||
|
%gy
|
||||||
|
(scot %p our.bowl)
|
||||||
|
%metadata-store
|
||||||
|
(scot %da now.bowl)
|
||||||
|
/app-indices
|
||||||
|
==
|
||||||
|
=| cards=(list card)
|
||||||
|
|-
|
||||||
|
?~ resources [cards this]
|
||||||
|
=, i.resources
|
||||||
|
=/ =group:group-store
|
||||||
|
=- (fall - *group:group-store)
|
||||||
|
(scry-for:do (unit group:group-store) %group-store group-path)
|
||||||
|
:: if we're the only group member, this got incorrectly ignored
|
||||||
|
:: during 0's upgrade logic. watch it now.
|
||||||
|
::
|
||||||
|
?. &(=(1 ~(wyt in group)) (~(has in group) our.bowl))
|
||||||
|
$(resources t.resources)
|
||||||
|
=^ more-cards state
|
||||||
|
(handle-listen-action:do %watch app-path)
|
||||||
|
$(resources t.resources, cards (weld more-cards cards))
|
||||||
|
::
|
||||||
|
%0
|
||||||
|
=/ listening=(set app-path)
|
||||||
|
(~(run in ~(key by reasoning.old)) tail)
|
||||||
|
$(old [%1 listening +.old])
|
||||||
|
==
|
||||||
::
|
::
|
||||||
++ on-agent
|
++ on-agent
|
||||||
|= [=wire =sign:agent:gall]
|
|= [=wire =sign:agent:gall]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?: ?=([%groups ~] wire)
|
=^ cards state
|
||||||
=^ cards state
|
?+ wire ~|([dap.bowl %weird-agent-wire wire] !!)
|
||||||
|
[%metadata ~]
|
||||||
|
(take-metadata-sign:do sign)
|
||||||
|
::
|
||||||
|
[%groups ~]
|
||||||
(take-groups-sign:do sign)
|
(take-groups-sign:do sign)
|
||||||
[cards this]
|
::
|
||||||
?: ?=([%links @ ^] wire)
|
[%links ?(%local-pages %annotations) @ ^]
|
||||||
=^ cards state
|
(take-link-sign:do (wire-to-target t.wire) sign)
|
||||||
(take-links-sign:do (slav %p i.t.wire) t.t.wire sign)
|
::
|
||||||
[cards this]
|
[%forward ^]
|
||||||
?: ?=([%forward ^] wire)
|
|
||||||
=^ cards state
|
|
||||||
(take-forward-sign:do t.wire sign)
|
(take-forward-sign:do t.wire sign)
|
||||||
|
::
|
||||||
|
[%prod *]
|
||||||
|
?> ?=(%poke-ack -.sign)
|
||||||
|
?~ p.sign [~ state]
|
||||||
|
%- (slog leaf+"prod failed" u.p.sign)
|
||||||
|
[~ state]
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ on-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
%link-listen-poke
|
||||||
|
=/ =path !<(path vase)
|
||||||
|
:_ this
|
||||||
|
%+ weld
|
||||||
|
(take-retry:do %local-pages src.bowl path)
|
||||||
|
(take-retry:do %annotations src.bowl path)
|
||||||
|
::
|
||||||
|
%link-listen-action
|
||||||
|
?> (team:title [our src]:bowl)
|
||||||
|
=^ cards state
|
||||||
|
~| p.vase
|
||||||
|
(handle-listen-action:do !<(action:link-listen-hook vase))
|
||||||
[cards this]
|
[cards this]
|
||||||
~| [dap.bowl %weird-wire wire]
|
==
|
||||||
!!
|
|
||||||
::
|
::
|
||||||
++ on-arvo
|
++ on-arvo
|
||||||
|= [=wire =sign-arvo]
|
|= [=wire =sign-arvo]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?. ?=([%g %done *] sign-arvo)
|
?+ sign-arvo (on-arvo:def wire sign-arvo)
|
||||||
(on-arvo:def wire sign-arvo)
|
[%g %done *]
|
||||||
?~ error.sign-arvo [~ this]
|
?~ error.sign-arvo [~ this]
|
||||||
=/ =tank leaf+"{(trip dap.bowl)}'s message went wrong!"
|
=/ =tank leaf+"{(trip dap.bowl)}'s message went wrong!"
|
||||||
%- (slog tank tang.u.error.sign-arvo)
|
%- (slog tank tang.u.error.sign-arvo)
|
||||||
[~ this]
|
[~ this]
|
||||||
|
::
|
||||||
|
[%b %wake *]
|
||||||
|
?> ?=([%retry @ @ ^] wire)
|
||||||
|
?^ error.sign-arvo
|
||||||
|
=/ =tank leaf+"wake on {(spud wire)} went wrong!"
|
||||||
|
%- (slog tank u.error.sign-arvo)
|
||||||
|
[~ this]
|
||||||
|
:_ this
|
||||||
|
(take-retry:do (wire-to-target t.wire))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-peek
|
||||||
|
|= =path
|
||||||
|
^- (unit (unit cage))
|
||||||
|
?+ path ~
|
||||||
|
[%x %listening ~] ``noun+!>(listening)
|
||||||
|
[%x %listening ^] ``noun+!>((~(has in listening) t.t.path))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?. ?=([%listening ~] path) (on-watch:def path)
|
||||||
|
?> (team:title [our src]:bowl)
|
||||||
|
:_ this
|
||||||
|
[%give %fact ~ %link-listen-update !>([%listening listening])]~
|
||||||
::
|
::
|
||||||
++ on-poke on-poke:def
|
|
||||||
++ on-peek on-peek:def
|
|
||||||
++ on-watch on-watch:def
|
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
++ on-fail on-fail:def
|
++ on-fail on-fail:def
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
::
|
::
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
|
+* md ~(. mdl bowl)
|
||||||
::
|
::
|
||||||
:: groups subscription
|
:: user actions & updates
|
||||||
|
::
|
||||||
|
++ handle-listen-action
|
||||||
|
|= =action:link-listen-hook
|
||||||
|
^- (quip card _state)
|
||||||
|
::NOTE no-opping where appropriate happens further down the call stack.
|
||||||
|
:: we *could* no-op here, as %watch when we're already listening should
|
||||||
|
:: result in no-ops all the way down, but walking through everything
|
||||||
|
:: makes this a nice "resurrect if broken unexpectedly" option.
|
||||||
|
::
|
||||||
|
=* app-path path.action
|
||||||
|
=^ cards listening
|
||||||
|
^- (quip card _listening)
|
||||||
|
=/ had=? (~(has in listening) app-path)
|
||||||
|
?- -.action
|
||||||
|
%watch
|
||||||
|
:_ (~(put in listening) app-path)
|
||||||
|
?:(had ~ [(send-update action)]~)
|
||||||
|
::
|
||||||
|
%leave
|
||||||
|
:_ (~(del in listening) app-path)
|
||||||
|
?.(had ~ [(send-update action)]~)
|
||||||
|
==
|
||||||
|
=/ groups=(list group-path)
|
||||||
|
(groups-from-resource:md %link app-path)
|
||||||
|
|-
|
||||||
|
?~ groups [cards state]
|
||||||
|
=^ more-cards state
|
||||||
|
?- -.action
|
||||||
|
%watch (listen-to-group app-path i.groups)
|
||||||
|
%leave (leave-from-group app-path i.groups)
|
||||||
|
==
|
||||||
|
$(cards (weld cards more-cards), groups t.groups)
|
||||||
|
::
|
||||||
|
++ send-update
|
||||||
|
|= =update:link-listen-hook
|
||||||
|
^- card
|
||||||
|
[%give %fact ~[/listening] %link-listen-update !>(update)]
|
||||||
|
::
|
||||||
|
:: metadata subscription
|
||||||
|
::
|
||||||
|
++ watch-metadata
|
||||||
|
^- card
|
||||||
|
[%pass /metadata %agent [our.bowl %metadata-store] %watch /app-name/link]
|
||||||
|
::
|
||||||
|
++ take-metadata-sign
|
||||||
|
|= =sign:agent:gall
|
||||||
|
^- (quip card _state)
|
||||||
|
?- -.sign
|
||||||
|
%poke-ack ~|([dap.bowl %unexpected-poke-ack /metadata] !!)
|
||||||
|
%kick [[watch-metadata]~ state]
|
||||||
|
::
|
||||||
|
%watch-ack
|
||||||
|
?~ p.sign [~ state]
|
||||||
|
=/ =tank
|
||||||
|
:- %leaf
|
||||||
|
"{(trip dap.bowl)} failed subscribe to metadata store. very wrong!"
|
||||||
|
%- (slog tank u.p.sign)
|
||||||
|
[~ state]
|
||||||
|
::
|
||||||
|
%fact
|
||||||
|
=* mark p.cage.sign
|
||||||
|
=* vase q.cage.sign
|
||||||
|
?. ?=(%metadata-update mark)
|
||||||
|
~| [dap.bowl %unexpected-mark mark]
|
||||||
|
!!
|
||||||
|
%- handle-metadata-update
|
||||||
|
!<(metadata-update vase)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-metadata-update
|
||||||
|
|= upd=metadata-update
|
||||||
|
^- (quip card _state)
|
||||||
|
?+ -.upd [~ state]
|
||||||
|
%add
|
||||||
|
?> =(%link app-name.resource.upd)
|
||||||
|
:: auto-listen to collections in unmanaged groups only
|
||||||
|
::
|
||||||
|
?. ?=([%'~' ^] group-path.upd) [~ state]
|
||||||
|
=, resource.upd
|
||||||
|
=^ update listening
|
||||||
|
^- (quip card _listening)
|
||||||
|
?: (~(has in listening) app-path)
|
||||||
|
[~ listening]
|
||||||
|
:- [(send-update %watch app-path)]~
|
||||||
|
(~(put in listening) app-path)
|
||||||
|
=^ cards state
|
||||||
|
(listen-to-group app-path group-path.upd)
|
||||||
|
[(weld update cards) state]
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
?> =(%link app-name.resource.upd)
|
||||||
|
=? listening
|
||||||
|
?=(~ (groups-from-resource:md %link app-path.resource.upd))
|
||||||
|
(~(del in listening) app-path.resource.upd)
|
||||||
|
(leave-from-group app-path.resource.upd group-path.upd)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: groups subscriptions
|
||||||
::
|
::
|
||||||
++ watch-groups
|
++ watch-groups
|
||||||
^- card
|
^- card
|
||||||
@ -106,111 +337,268 @@
|
|||||||
%fact
|
%fact
|
||||||
=* mark p.cage.sign
|
=* mark p.cage.sign
|
||||||
=* vase q.cage.sign
|
=* vase q.cage.sign
|
||||||
~& [dap.bowl %fact mark]
|
|
||||||
?+ mark ~|([dap.bowl %unexpected-mark mark] !!)
|
?+ mark ~|([dap.bowl %unexpected-mark mark] !!)
|
||||||
%group-initial (handle-group-initial !<(groups:group-store vase))
|
%group-initial [~ state] ::NOTE initial handled using metadata
|
||||||
%group-update (handle-group-update !<(group-update:group-store vase))
|
%group-update (handle-group-update !<(group-update:group-store vase))
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ handle-group-initial
|
|
||||||
|= =groups:group-store
|
|
||||||
^- (quip card _state)
|
|
||||||
=| cards=(list card)
|
|
||||||
=/ groups=(list [=path =group:group-store])
|
|
||||||
~(tap by groups)
|
|
||||||
|-
|
|
||||||
?~ groups [cards state]
|
|
||||||
=^ caz state
|
|
||||||
%- handle-group-update
|
|
||||||
[%add [group path]:i.groups]
|
|
||||||
$(cards (weld cards caz), groups t.groups)
|
|
||||||
::
|
|
||||||
++ handle-group-update
|
++ handle-group-update
|
||||||
|= upd=group-update:group-store
|
|= upd=group-update:group-store
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
:_ state
|
?. ?=(?(%path %add %remove) -.upd)
|
||||||
?+ -.upd ~
|
[~ state]
|
||||||
?(%path %add %remove)
|
=/ socs=(list app-path)
|
||||||
=/ whos=(list ship) ~(tap in members.upd)
|
(app-paths-from-group:md %link pax.upd)
|
||||||
|- ^- (list card)
|
=/ whos=(list ship)
|
||||||
?~ whos ~
|
~(tap in members.upd)
|
||||||
:: no need to subscribe to ourselves
|
=| cards=(list card)
|
||||||
::
|
|-
|
||||||
|
=* loop-socs $
|
||||||
|
?~ socs [cards state]
|
||||||
|
?. (~(has in listening) i.socs)
|
||||||
|
loop-socs(socs t.socs)
|
||||||
|
|-
|
||||||
|
=* loop-whos $
|
||||||
|
?~ whos loop-socs(socs t.socs)
|
||||||
|
=^ caz state
|
||||||
|
?. ?=(%remove -.upd)
|
||||||
|
(listen-to-peer i.socs pax.upd i.whos)
|
||||||
?: =(our.bowl i.whos)
|
?: =(our.bowl i.whos)
|
||||||
$(whos t.whos)
|
(handle-listen-action %leave i.socs)
|
||||||
:_ $(whos t.whos)
|
(leave-from-peer i.socs pax.upd i.whos)
|
||||||
%. [i.whos pax.upd]
|
loop-whos(whos t.whos, cards (weld cards caz))
|
||||||
?: ?=(%remove -.upd)
|
|
||||||
end-link-subscription
|
|
||||||
start-link-subscription
|
|
||||||
==
|
|
||||||
::
|
::
|
||||||
:: link subscriptions
|
:: link subscriptions
|
||||||
::
|
::
|
||||||
|
++ listen-to-group
|
||||||
|
|= [=app-path =group-path]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ peers=(list ship)
|
||||||
|
~| group-path
|
||||||
|
%~ tap in
|
||||||
|
=- (fall - *group:group-store)
|
||||||
|
%^ scry-for (unit group:group-store)
|
||||||
|
%group-store
|
||||||
|
group-path
|
||||||
|
=| cards=(list card)
|
||||||
|
|-
|
||||||
|
?~ peers [cards state]
|
||||||
|
=^ caz state
|
||||||
|
(listen-to-peer app-path group-path i.peers)
|
||||||
|
$(peers t.peers, cards (weld cards caz))
|
||||||
|
::
|
||||||
|
++ leave-from-group
|
||||||
|
|= [=app-path =group-path]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ peers=(list ship)
|
||||||
|
%~ tap in
|
||||||
|
=- (fall - *group:group-store)
|
||||||
|
%^ scry-for (unit group:group-store)
|
||||||
|
%group-store
|
||||||
|
group-path
|
||||||
|
=| cards=(list card)
|
||||||
|
|-
|
||||||
|
?~ peers [cards state]
|
||||||
|
=^ caz state
|
||||||
|
(leave-from-peer app-path group-path i.peers)
|
||||||
|
$(peers t.peers, cards (weld cards caz))
|
||||||
|
::
|
||||||
|
++ listen-to-peer
|
||||||
|
|= [=app-path =group-path who=ship]
|
||||||
|
^- (quip card _state)
|
||||||
|
?: =(our.bowl who)
|
||||||
|
[~ state]
|
||||||
|
:_ =- state(reasoning -)
|
||||||
|
(~(put ju reasoning) [who app-path] group-path)
|
||||||
|
:- (prod-other-listener who app-path)
|
||||||
|
?^ (~(get ju reasoning) [who app-path])
|
||||||
|
~
|
||||||
|
(start-link-subscriptions who app-path)
|
||||||
|
::
|
||||||
|
++ leave-from-peer
|
||||||
|
|= [=app-path =group-path who=ship]
|
||||||
|
^- (quip card _state)
|
||||||
|
?: =(our.bowl who)
|
||||||
|
[~ state]
|
||||||
|
=. reasoning (~(del ju reasoning) [who app-path] group-path)
|
||||||
|
::NOTE leaving is always safe, so we just do it unconditionally
|
||||||
|
(end-link-subscriptions who app-path)
|
||||||
|
::
|
||||||
|
++ start-link-subscriptions
|
||||||
|
|= [=ship =app-path]
|
||||||
|
^- (list card)
|
||||||
|
:~ (start-link-subscription %local-pages ship app-path)
|
||||||
|
(start-link-subscription %annotations ship app-path)
|
||||||
|
==
|
||||||
|
::
|
||||||
++ start-link-subscription
|
++ start-link-subscription
|
||||||
|= [who=ship where=path]
|
|= =target
|
||||||
^- card
|
^- card
|
||||||
:* %pass
|
:* %pass
|
||||||
[%links (scot %p who) where]
|
[%links (target-to-wire target)]
|
||||||
%agent
|
%agent
|
||||||
[who %link-proxy-hook]
|
[who.target %link-proxy-hook]
|
||||||
%watch
|
%watch
|
||||||
[%local-pages where]
|
?- what.target
|
||||||
|
%local-pages [what where]:target
|
||||||
|
%annotations [what %$ where]:target
|
||||||
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ end-link-subscription
|
++ end-link-subscriptions
|
||||||
|
|= [who=ship where=path]
|
||||||
|
^- (quip card _state)
|
||||||
|
=. retry-timers (~(del by retry-timers) [%local-pages who where])
|
||||||
|
=. retry-timers (~(del by retry-timers) [%annotations who where])
|
||||||
|
:_ state
|
||||||
|
|^ ~[(end %local-pages) (end %annotations)]
|
||||||
|
::
|
||||||
|
++ end
|
||||||
|
|= what=what-target
|
||||||
|
:* %pass
|
||||||
|
[%links (target-to-wire what who where)]
|
||||||
|
%agent
|
||||||
|
[who %link-proxy-hook]
|
||||||
|
%leave
|
||||||
|
~
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ prod-other-listener
|
||||||
|= [who=ship where=path]
|
|= [who=ship where=path]
|
||||||
^- card
|
^- card
|
||||||
:* %pass
|
:* %pass
|
||||||
[%links (scot %p who) where]
|
[%prod (scot %p who) where]
|
||||||
%agent
|
%agent
|
||||||
[who %link-proxy-hook]
|
[who %link-listen-hook]
|
||||||
%leave
|
%poke
|
||||||
~
|
%link-listen-poke
|
||||||
|
!>(where)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ take-links-sign
|
++ take-link-sign
|
||||||
|= [who=ship where=path =sign:agent:gall]
|
|= [=target =sign:agent:gall]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?- -.sign
|
?- -.sign
|
||||||
%poke-ack ~|([dap.bowl %unexpected-poke-ack /links who where] !!)
|
%poke-ack ~|([dap.bowl %unexpected-poke-ack /links target] !!)
|
||||||
%kick [[(start-link-subscription who where)]~ state]
|
%kick [[(start-link-subscription target)]~ state]
|
||||||
::
|
::
|
||||||
%watch-ack
|
%watch-ack
|
||||||
?~ p.sign [~ state]
|
?~ p.sign
|
||||||
:: our subscription request got rejected for whatever reason,
|
=. retry-timers (~(del by retry-timers) target)
|
||||||
:: (most likely difference in group membership,)
|
[~ state]
|
||||||
:: so we don't try again.
|
:: our subscription request got rejected,
|
||||||
::TODO but now the only way to retry is to remove from group and re-add...
|
:: most likely because our group definition is out of sync with theirs.
|
||||||
:: this is a problem because our and their group may not update
|
:: set timer for retry.
|
||||||
:: simultaneously...
|
::
|
||||||
[~ state]
|
(start-retry target)
|
||||||
::
|
::
|
||||||
%fact
|
%fact
|
||||||
=* mark p.cage.sign
|
=* mark p.cage.sign
|
||||||
=* vase q.cage.sign
|
=* vase q.cage.sign
|
||||||
?+ mark ~|([dap.bowl %unexpected-mark mark] !!)
|
?+ mark ~|([dap.bowl %unexpected-mark mark] !!)
|
||||||
%link-update (handle-link-update who where !<(update vase))
|
%link-initial
|
||||||
|
%- handle-link-initial
|
||||||
|
[who.target where.target !<(initial vase)]
|
||||||
|
::
|
||||||
|
%link-update
|
||||||
|
%- handle-link-update
|
||||||
|
[who.target where.target !<(update vase)]
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
++ start-retry
|
||||||
|
|= =target
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ timer=@dr
|
||||||
|
%+ min ~h1
|
||||||
|
%+ mul 2
|
||||||
|
(~(gut by retry-timers) target ~s15)
|
||||||
|
=. retry-timers
|
||||||
|
(~(put by retry-timers) target timer)
|
||||||
|
:_ state
|
||||||
|
:_ ~
|
||||||
|
:* %pass
|
||||||
|
[%retry (target-to-wire target)]
|
||||||
|
[%arvo %b %wait (add now.bowl timer)]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ take-retry
|
||||||
|
|= =target
|
||||||
|
^- (list card)
|
||||||
|
:: relevant: whether :who is still associated with resource :where
|
||||||
|
::
|
||||||
|
=; relevant=?
|
||||||
|
?. relevant ~
|
||||||
|
[(start-link-subscription target)]~
|
||||||
|
?. (~(has in listening) where.target)
|
||||||
|
|
|
||||||
|
?: %- ~(has by wex.bowl)
|
||||||
|
[[%links (target-to-wire target)] who.target %link-proxy-hook]
|
||||||
|
|
|
||||||
|
%+ lien (groups-from-resource:md %link where.target)
|
||||||
|
|= =group-path
|
||||||
|
^- ?
|
||||||
|
=- (~(has in (fall - *group:group-store)) who.target)
|
||||||
|
%^ scry-for (unit group:group-store)
|
||||||
|
%group-store
|
||||||
|
group-path
|
||||||
|
::
|
||||||
|
++ do-link-action
|
||||||
|
|= [=wire =action]
|
||||||
|
^- card
|
||||||
|
:* %pass
|
||||||
|
wire
|
||||||
|
%agent
|
||||||
|
[our.bowl %link-store]
|
||||||
|
%poke
|
||||||
|
%link-action
|
||||||
|
!>(action)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-link-initial
|
||||||
|
|= [who=ship where=path =initial]
|
||||||
|
^- (quip card _state)
|
||||||
|
?> =(src.bowl who)
|
||||||
|
?+ -.initial ~|([dap.bowl %unexpected-initial -.initial] !!)
|
||||||
|
%local-pages
|
||||||
|
=/ =pages (~(got by pages.initial) where)
|
||||||
|
(handle-link-update who where [%local-pages where pages])
|
||||||
|
::
|
||||||
|
%annotations
|
||||||
|
=/ urls=(list [=url =notes])
|
||||||
|
~(tap by (~(got by notes.initial) where))
|
||||||
|
=| cards=(list card)
|
||||||
|
|- ^- (quip card _state)
|
||||||
|
?~ urls [cards state]
|
||||||
|
=^ caz state
|
||||||
|
^- (quip card _state)
|
||||||
|
=, i.urls
|
||||||
|
(handle-link-update who where [%annotations where url notes])
|
||||||
|
$(urls t.urls, cards (weld cards caz))
|
||||||
|
==
|
||||||
|
::
|
||||||
++ handle-link-update
|
++ handle-link-update
|
||||||
|= [who=ship where=path =update]
|
|= [who=ship where=path =update]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?> ?=(%local-pages -.update)
|
|
||||||
?> =(src.bowl who)
|
?> =(src.bowl who)
|
||||||
:_ state
|
:_ state
|
||||||
%+ turn pages.update
|
?+ -.update ~|([dap.bowl %unexpected-update -.update] !!)
|
||||||
|= =page
|
%local-pages
|
||||||
^- card
|
%+ turn pages.update
|
||||||
:* %pass
|
|= =page
|
||||||
[%forward (scot %p who) where]
|
%+ do-link-action
|
||||||
%agent
|
[%forward %local-page (scot %p who) where]
|
||||||
[our.bowl %link-store]
|
[%hear where who page]
|
||||||
%poke
|
::
|
||||||
%link-action
|
%annotations
|
||||||
!>([%hear where src.bowl page])
|
%+ turn notes.update
|
||||||
|
|= =note
|
||||||
|
^- card
|
||||||
|
%+ do-link-action
|
||||||
|
[%forward %annotation (scot %p who) where]
|
||||||
|
[%read where url.update who note]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ take-forward-sign
|
++ take-forward-sign
|
||||||
@ -228,4 +616,14 @@
|
|||||||
==
|
==
|
||||||
%- (slog tank u.p.sign)
|
%- (slog tank u.p.sign)
|
||||||
[~ state]
|
[~ state]
|
||||||
|
::
|
||||||
|
++ scry-for
|
||||||
|
|* [=mold =app-name =path]
|
||||||
|
.^ mold
|
||||||
|
%gx
|
||||||
|
(scot %p our.bowl)
|
||||||
|
app-name
|
||||||
|
(scot %da now.bowl)
|
||||||
|
(snoc `^path`path %noun)
|
||||||
|
==
|
||||||
--
|
--
|
||||||
|
@ -4,12 +4,11 @@
|
|||||||
:: stores if permission conditions are met.
|
:: stores if permission conditions are met.
|
||||||
:: the patterns herein should one day be generalized into a proxy-hook lib.
|
:: the patterns herein should one day be generalized into a proxy-hook lib.
|
||||||
::
|
::
|
||||||
:: this adopts a very primitive view of groups-store as containing only
|
:: this uses metadata-store to discover resources and their associated
|
||||||
:: groups of interesting (rather than uninteresting) ships. it sets the
|
:: groups. it sets the permission condition to be that a ship must be in a
|
||||||
:: permission condition to be that ship must be in group matching the path
|
:: group associated with the resource it's subscribing to.
|
||||||
:: it's subscribing to.
|
:: we check this on-watch, but also subscribe to metadata & groups so that
|
||||||
:: we check this on-watch, but also subscribe to groups so that we can kick
|
:: we can kick subscriptions if needed (eg ship removed from group).
|
||||||
:: subscriptions if needed (eg ship removed from group).
|
|
||||||
::
|
::
|
||||||
:: we deduplicate incoming subscriptions on the same path, ensuring we have
|
:: we deduplicate incoming subscriptions on the same path, ensuring we have
|
||||||
:: exactly one local subscription per unique incoming subscription path.
|
:: exactly one local subscription per unique incoming subscription path.
|
||||||
@ -17,8 +16,12 @@
|
|||||||
:: whatever's returned by the scry at that path, but perhaps that should
|
:: whatever's returned by the scry at that path, but perhaps that should
|
||||||
:: become part of the stores standard anyway.
|
:: become part of the stores standard anyway.
|
||||||
::
|
::
|
||||||
/- *link, group-store
|
:: when adding support for new paths, the only things you'll likely want
|
||||||
/+ default-agent, verb
|
:: to touch are +permitted, +initial-response, & +kick-proxies.
|
||||||
|
::
|
||||||
|
/- group-store, *metadata-store
|
||||||
|
/+ *link, metadata, default-agent, verb, dbug
|
||||||
|
~% %link-proxy-hook-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ state-0
|
+$ state-0
|
||||||
$: %0
|
$: %0
|
||||||
@ -33,6 +36,7 @@
|
|||||||
=| state-0
|
=| state-0
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
|
%- agent:dbug
|
||||||
%+ verb |
|
%+ verb |
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
@ -44,7 +48,7 @@
|
|||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
:_ this
|
:_ this
|
||||||
[watch-groups:do]~
|
~[watch-groups:do watch-metadata:do]
|
||||||
::
|
::
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
++ on-load
|
++ on-load
|
||||||
@ -92,24 +96,92 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
|
+* md ~(. metadata bowl)
|
||||||
|
::
|
||||||
|
:: permissions
|
||||||
|
::
|
||||||
++ permitted
|
++ permitted
|
||||||
|= [who=ship =path]
|
|= [who=ship =path]
|
||||||
^- ?
|
^- ?
|
||||||
:: we only expose /local-pages, and only to ships in the relevant group
|
:: we only expose /local-pages and /annotations,
|
||||||
|
:: to ships in the groups associated with the resource.
|
||||||
|
:: (no url-specific annotations subscriptions, either.)
|
||||||
::
|
::
|
||||||
?. ?=([%local-pages ^] path) |
|
=/ target=(unit ^path)
|
||||||
=; group
|
?: ?=([%local-pages ^] path)
|
||||||
?& ?=(^ group)
|
`t.path
|
||||||
(~(has in u.group) who)
|
?: ?=([%annotations ~ ^] path)
|
||||||
==
|
`t.t.path
|
||||||
.^ (unit group:group-store)
|
~
|
||||||
%gx
|
?~ target |
|
||||||
(scot %p our.bowl)
|
%+ lien (groups-from-resource:md %link u.target)
|
||||||
%group-store
|
|= =group-path
|
||||||
(scot %da now.bowl)
|
^- ?
|
||||||
(snoc t.path %noun)
|
=- (~(has in (fall - *group:group-store)) who)
|
||||||
|
%^ scry-for (unit group:group-store)
|
||||||
|
%group-store
|
||||||
|
group-path
|
||||||
|
::
|
||||||
|
++ kick-revoked-permissions
|
||||||
|
|= [=path who=(list ship)]
|
||||||
|
^- (list card)
|
||||||
|
%+ murn who
|
||||||
|
|= =ship
|
||||||
|
^- (unit card)
|
||||||
|
:: no need to remove to ourselves
|
||||||
|
::
|
||||||
|
?: =(our.bowl ship) ~
|
||||||
|
?: (permitted ship path) ~
|
||||||
|
`(kick-proxies ship path)
|
||||||
|
::
|
||||||
|
:: metadata subscription
|
||||||
|
::
|
||||||
|
++ watch-metadata
|
||||||
|
^- card
|
||||||
|
[%pass /metadata %agent [our.bowl %metadata-store] %watch /app-name/link]
|
||||||
|
::
|
||||||
|
++ take-metadata-sign
|
||||||
|
|= =sign:agent:gall
|
||||||
|
^- (quip card _state)
|
||||||
|
?- -.sign
|
||||||
|
%poke-ack ~|([dap.bowl %unexpected-poke-ack /metadata] !!)
|
||||||
|
%kick [[watch-metadata]~ state]
|
||||||
|
::
|
||||||
|
%watch-ack
|
||||||
|
?~ p.sign [~ state]
|
||||||
|
=/ =tank
|
||||||
|
:- %leaf
|
||||||
|
"{(trip dap.bowl)} failed subscribe to metadata store. very wrong!"
|
||||||
|
%- (slog tank u.p.sign)
|
||||||
|
[~ state]
|
||||||
|
::
|
||||||
|
%fact
|
||||||
|
=* mark p.cage.sign
|
||||||
|
=* vase q.cage.sign
|
||||||
|
?. ?=(%metadata-update mark)
|
||||||
|
~| [dap.bowl %unexpected-mark mark]
|
||||||
|
!!
|
||||||
|
%- handle-metadata-update
|
||||||
|
!<(metadata-update vase)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
++ handle-metadata-update
|
||||||
|
|= upd=metadata-update
|
||||||
|
^- (quip card _state)
|
||||||
|
:_ state
|
||||||
|
?. ?=(%remove -.upd) ~
|
||||||
|
?> =(%link app-name.resource.upd)
|
||||||
|
:: if a group is no longer associated with a resource,
|
||||||
|
:: we need to re-check permissions for everyone in that group.
|
||||||
|
::
|
||||||
|
%+ kick-revoked-permissions
|
||||||
|
app-path.resource.upd
|
||||||
|
%~ tap in
|
||||||
|
=- (fall - *group:group-store)
|
||||||
|
%^ scry-for (unit group:group-store)
|
||||||
|
%group-store
|
||||||
|
group-path.upd
|
||||||
|
::
|
||||||
:: groups subscription
|
:: groups subscription
|
||||||
::TODO largely copied from link-listen-hook. maybe make a store-listener lib?
|
::TODO largely copied from link-listen-hook. maybe make a store-listener lib?
|
||||||
::
|
::
|
||||||
@ -135,7 +207,6 @@
|
|||||||
%fact
|
%fact
|
||||||
=* mark p.cage.sign
|
=* mark p.cage.sign
|
||||||
=* vase q.cage.sign
|
=* vase q.cage.sign
|
||||||
~& [dap.bowl %fact mark]
|
|
||||||
?+ mark ~|([dap.bowl %unexpected-mark mark] !!)
|
?+ mark ~|([dap.bowl %unexpected-mark mark] !!)
|
||||||
%group-initial [~ state]
|
%group-initial [~ state]
|
||||||
%group-update (handle-group-update !<(group-update:group-store vase))
|
%group-update (handle-group-update !<(group-update:group-store vase))
|
||||||
@ -147,33 +218,34 @@
|
|||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
:_ state
|
:_ state
|
||||||
?. ?=(%remove -.upd) ~
|
?. ?=(%remove -.upd) ~
|
||||||
=/ whos=(list ship) ~(tap in members.upd)
|
:: if someone was removed from a group, find all link resources associated
|
||||||
|- ^- (list card)
|
:: with that group, then kick their subscriptions if they're no longer
|
||||||
?~ whos ~
|
|
||||||
:: no need to remove to ourselves
|
|
||||||
::
|
::
|
||||||
?: =(our.bowl i.whos)
|
%- zing
|
||||||
$(whos t.whos)
|
%+ turn (app-paths-from-group:md %link pax.upd)
|
||||||
:_ $(whos t.whos)
|
|= =app-path
|
||||||
::NOTE this depends kind of unfortunately on the fact that we only accept
|
^- (list card)
|
||||||
:: subscriptions to /local-pages/* paths. it'd be more correct if we
|
%+ kick-revoked-permissions
|
||||||
:: "just" looked at all paths in the map, and found the matching ones.
|
app-path
|
||||||
(kick-proxy i.whos [%local-pages pax.upd])
|
~(tap in members.upd)
|
||||||
::
|
::
|
||||||
:: proxy subscriptions
|
:: proxy subscriptions
|
||||||
::
|
::
|
||||||
++ kick-proxy
|
++ kick-proxies
|
||||||
|= [who=ship =path]
|
|= [who=ship =path]
|
||||||
^- card
|
^- card
|
||||||
[%give %kick ~[path] `who]
|
=- [%give %kick - `who]
|
||||||
|
:~ [%local-pages path]
|
||||||
|
[%annotations %$ path]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
++ handle-proxy-sign
|
++ handle-proxy-sign
|
||||||
|= [=path =sign:agent:gall]
|
|= [=wire =sign:agent:gall]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?- -.sign
|
?- -.sign
|
||||||
%poke-ack ~|([dap.bowl %unexpected-poke-ack path] !!)
|
%poke-ack ~|([dap.bowl %unexpected-poke-ack wire] !!)
|
||||||
%fact [[%give %fact ~[path] cage.sign]~ state]
|
%fact [[%give %fact ~[wire] cage.sign]~ state]
|
||||||
%kick [[(proxy-pass-link-store path %watch path)]~ state]
|
%kick [[(proxy-pass-link-store wire %watch wire)]~ state]
|
||||||
::
|
::
|
||||||
%watch-ack
|
%watch-ack
|
||||||
?~ p.sign [~ state]
|
?~ p.sign [~ state]
|
||||||
@ -197,9 +269,15 @@
|
|||||||
++ initial-response
|
++ initial-response
|
||||||
|= =path
|
|= =path
|
||||||
^- card
|
^- card
|
||||||
=/ initial=update
|
=; =initial
|
||||||
[%local-pages path .^(pages %gx path)]
|
[%give %fact ~ %link-initial !>(initial)]
|
||||||
[%give %fact ~ %link-update !>(initial)]
|
?+ path !!
|
||||||
|
[%local-pages ^]
|
||||||
|
[%local-pages (scry-for (map ^path pages) %link-store path)]
|
||||||
|
::
|
||||||
|
[%annotations %$ ^]
|
||||||
|
[%annotations (scry-for (per-path-url notes) %link-store path)]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
++ start-proxy
|
++ start-proxy
|
||||||
|= [who=ship =path]
|
|= [who=ship =path]
|
||||||
@ -228,4 +306,16 @@
|
|||||||
:: else, close the local subscription.
|
:: else, close the local subscription.
|
||||||
::
|
::
|
||||||
[(proxy-pass-link-store path %leave ~)]~
|
[(proxy-pass-link-store path %leave ~)]~
|
||||||
|
::
|
||||||
|
:: helpers
|
||||||
|
::
|
||||||
|
++ scry-for
|
||||||
|
|* [=mold =app-name =path]
|
||||||
|
.^ mold
|
||||||
|
%gx
|
||||||
|
(scot %p our.bowl)
|
||||||
|
app-name
|
||||||
|
(scot %da now.bowl)
|
||||||
|
(snoc `^path`path %noun)
|
||||||
|
==
|
||||||
--
|
--
|
||||||
|
@ -1,228 +0,0 @@
|
|||||||
:: link-server: accessing link-store via eyre
|
|
||||||
::
|
|
||||||
:: only accepts requests authenticated as the host ship.
|
|
||||||
::
|
|
||||||
:: GET requests:
|
|
||||||
:: /~link/local-pages/[some-path].json?p=0
|
|
||||||
:: our submissions on path, with optional pagination
|
|
||||||
::
|
|
||||||
:: POST requests:
|
|
||||||
:: /~link/add/[some-path]
|
|
||||||
:: send {title url} json, will save link at path
|
|
||||||
::
|
|
||||||
/+ *link, *server, default-agent, verb
|
|
||||||
::
|
|
||||||
|%
|
|
||||||
+$ state-0
|
|
||||||
$: %0
|
|
||||||
~
|
|
||||||
::NOTE this means we could get away with just producing cards everywhere,
|
|
||||||
:: never producing new state outside of the agent interface core.
|
|
||||||
:: we opt to keep ^-(quip card _state) in place for most logic arms
|
|
||||||
:: because it doesn't cost much, results in unsurprising code, and
|
|
||||||
:: makes adding any state in the future easier.
|
|
||||||
==
|
|
||||||
::
|
|
||||||
+$ card card:agent:gall
|
|
||||||
--
|
|
||||||
::
|
|
||||||
=| state-0
|
|
||||||
=* state -
|
|
||||||
::
|
|
||||||
%+ verb |
|
|
||||||
^- agent:gall
|
|
||||||
=<
|
|
||||||
|_ =bowl:gall
|
|
||||||
+* this .
|
|
||||||
do ~(. +> bowl)
|
|
||||||
def ~(. (default-agent this %|) bowl)
|
|
||||||
::
|
|
||||||
++ on-init
|
|
||||||
^- (quip card _this)
|
|
||||||
:_ this
|
|
||||||
[start-serving:do]~
|
|
||||||
::
|
|
||||||
++ on-save !>(state)
|
|
||||||
++ on-load
|
|
||||||
|= old=vase
|
|
||||||
^- (quip card _this)
|
|
||||||
[~ this(state !<(state-0 old))]
|
|
||||||
::
|
|
||||||
++ on-watch
|
|
||||||
|= =path
|
|
||||||
^- (quip card _this)
|
|
||||||
?: ?=([%http-response *] path)
|
|
||||||
[~ this]
|
|
||||||
(on-watch:def path)
|
|
||||||
::
|
|
||||||
++ on-poke
|
|
||||||
|= [=mark =vase]
|
|
||||||
^- (quip card _this)
|
|
||||||
?. ?=(%handle-http-request mark)
|
|
||||||
(on-poke:def mark vase)
|
|
||||||
:_ this
|
|
||||||
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
|
|
||||||
(handle-http-request:do eyre-id inbound-request)
|
|
||||||
::
|
|
||||||
++ on-arvo
|
|
||||||
|= [=wire =sign-arvo]
|
|
||||||
^- (quip card _this)
|
|
||||||
?. ?=(%bound +<.sign-arvo)
|
|
||||||
(on-arvo:def wire sign-arvo)
|
|
||||||
[~ this]
|
|
||||||
::
|
|
||||||
++ on-agent
|
|
||||||
|= [=wire =sign:agent:gall]
|
|
||||||
^- (quip card _this)
|
|
||||||
?. ?=(%poke-ack -.sign)
|
|
||||||
(on-agent:def wire sign)
|
|
||||||
?~ p.sign [~ this]
|
|
||||||
=/ =tank
|
|
||||||
leaf+"{(trip dap.bowl)} failed writing to %link-store"
|
|
||||||
%- (slog tank u.p.sign)
|
|
||||||
[~ this]
|
|
||||||
::
|
|
||||||
++ on-peek on-peek:def
|
|
||||||
++ on-leave on-leave:def
|
|
||||||
++ on-fail on-fail:def
|
|
||||||
--
|
|
||||||
::
|
|
||||||
|_ =bowl:gall
|
|
||||||
::
|
|
||||||
++ start-serving
|
|
||||||
^- card
|
|
||||||
[%pass / %arvo %e %connect [~ /'~link'] dap.bowl]
|
|
||||||
::
|
|
||||||
++ do-action
|
|
||||||
|= =action
|
|
||||||
^- card
|
|
||||||
[%pass / %agent [our.bowl %link-store] %poke %link-action !>(action)]
|
|
||||||
::
|
|
||||||
++ do-add
|
|
||||||
|= [=path title=@t =url]
|
|
||||||
^- card
|
|
||||||
(do-action %add path title url)
|
|
||||||
::
|
|
||||||
++ handle-http-request
|
|
||||||
|= [eyre-id=@ta =inbound-request:eyre]
|
|
||||||
^- (list card)
|
|
||||||
::NOTE we don't use +require-authorization because it's too restrictive
|
|
||||||
:: on the flow we want here.
|
|
||||||
::
|
|
||||||
?. ?& authenticated.inbound-request
|
|
||||||
=(src.bowl our.bowl)
|
|
||||||
==
|
|
||||||
::TODO `*octs -> ~ everywhere once no-data bug is fixed
|
|
||||||
(give-simple-payload:app eyre-id [[403 ~] `*octs])
|
|
||||||
:: request-line: parsed url + params
|
|
||||||
::
|
|
||||||
=/ =request-line
|
|
||||||
%- parse-request-line
|
|
||||||
url.request.inbound-request
|
|
||||||
=* req-head header-list.request.inbound-request
|
|
||||||
=; [cards=(list card) =simple-payload:http]
|
|
||||||
%+ weld cards
|
|
||||||
(give-simple-payload:app eyre-id simple-payload)
|
|
||||||
?+ method.request.inbound-request [~ not-found:gen]
|
|
||||||
%'OPTIONS'
|
|
||||||
[~ (include-cors-headers req-head [[200 ~] `*octs])]
|
|
||||||
::
|
|
||||||
%'GET'
|
|
||||||
[~ (handle-get req-head request-line)]
|
|
||||||
::
|
|
||||||
%'POST'
|
|
||||||
(handle-post req-head request-line body.request.inbound-request)
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ handle-post
|
|
||||||
|= [request-headers=header-list:http =request-line body=(unit octs)]
|
|
||||||
^- [(list card) simple-payload:http]
|
|
||||||
=; [success=? cards=(list card)]
|
|
||||||
:- cards
|
|
||||||
%+ include-cors-headers
|
|
||||||
request-headers
|
|
||||||
::TODO it would be more correct to wait for the %poke-ack instead of
|
|
||||||
:: sending this response right away... but link-store pokes can't
|
|
||||||
:: actually fail right now, so it's fine.
|
|
||||||
[[?:(success 200 400) ~] `*octs]
|
|
||||||
?~ body [| ~]
|
|
||||||
?+ request-line [| ~]
|
|
||||||
[[~ [%'~link' %add ^]] ~]
|
|
||||||
^- [? (list card)]
|
|
||||||
=/ jon=(unit json) (de-json:html q.u.body)
|
|
||||||
?~ jon [| ~]
|
|
||||||
=/ page=(unit [title=@t =url])
|
|
||||||
%. u.jon
|
|
||||||
(ot title+so url+so ~):dejs-soft:format
|
|
||||||
?~ page [| ~]
|
|
||||||
[& [(do-add t.t.site.request-line [title url]:u.page) ~]]
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ handle-get
|
|
||||||
|= [request-headers=header-list:http =request-line]
|
|
||||||
%+ include-cors-headers
|
|
||||||
request-headers
|
|
||||||
^- simple-payload:http
|
|
||||||
:: args: map of params
|
|
||||||
:: p: pagination index
|
|
||||||
::
|
|
||||||
=/ args
|
|
||||||
%- ~(gas by *(map @t @t))
|
|
||||||
args.request-line
|
|
||||||
=/ p=(unit @ud)
|
|
||||||
%+ biff (~(get by args) 'p')
|
|
||||||
(curr rush dim:ag)
|
|
||||||
?+ request-line not-found:gen
|
|
||||||
::TODO expose submissions, other data
|
|
||||||
:: local links by recency as json
|
|
||||||
::
|
|
||||||
[[[~ %json] [%'~link' %local-pages ^]] *]
|
|
||||||
%- json-response:gen
|
|
||||||
%- json-to-octs ::TODO include in +json-response:gen
|
|
||||||
^- json
|
|
||||||
:- %a
|
|
||||||
%+ turn
|
|
||||||
`pages`(get-pages t.t.site.request-line p)
|
|
||||||
`$-(page json)`page:en-json
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ include-cors-headers
|
|
||||||
|= [request-headers=header-list:http =simple-payload:http]
|
|
||||||
^+ simple-payload
|
|
||||||
=* out-heads headers.response-header.simple-payload
|
|
||||||
=; =header-list:http
|
|
||||||
|-
|
|
||||||
?~ header-list simple-payload
|
|
||||||
=* new-head i.header-list
|
|
||||||
=. out-heads
|
|
||||||
(set-header:http key.new-head value.new-head out-heads)
|
|
||||||
$(header-list t.header-list)
|
|
||||||
=/ origin=@t
|
|
||||||
=/ headers=(map @t @t)
|
|
||||||
(~(gas by *(map @t @t)) request-headers)
|
|
||||||
(~(gut by headers) 'origin' '*')
|
|
||||||
:~ 'Access-Control-Allow-Origin'^origin
|
|
||||||
'Access-Control-Allow-Credentials'^'true'
|
|
||||||
'Access-Control-Request-Method'^'OPTIONS, GET, POST'
|
|
||||||
'Access-Control-Allow-Methods'^'OPTIONS, GET, POST'
|
|
||||||
'Access-Control-Allow-Headers'^'content-type'
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ page-size 25
|
|
||||||
++ get-pages
|
|
||||||
|= [=path p=(unit @ud)]
|
|
||||||
^- pages
|
|
||||||
=; =pages
|
|
||||||
?~ p pages
|
|
||||||
%+ scag page-size
|
|
||||||
%+ slag (mul u.p page-size)
|
|
||||||
pages
|
|
||||||
.^ pages
|
|
||||||
%gx
|
|
||||||
(scot %p our.bowl)
|
|
||||||
%link-store
|
|
||||||
(scot %da now.bowl)
|
|
||||||
%local-pages
|
|
||||||
(snoc path %noun)
|
|
||||||
==
|
|
||||||
--
|
|
@ -5,24 +5,71 @@
|
|||||||
:: links, arbitrary paths are probably fair game, but could trip up
|
:: links, arbitrary paths are probably fair game, but could trip up
|
||||||
:: primitive ui implementations.
|
:: primitive ui implementations.
|
||||||
::
|
::
|
||||||
|
:: urls in paths are expected to be encoded using +wood, for @ta sanity.
|
||||||
|
:: generally, use /lib/link's +build-discussion-path.
|
||||||
|
::
|
||||||
|
:: see link-listen-hook to see what's synced in, and similarly
|
||||||
|
:: see link-proxy-hook to see what's exposed.
|
||||||
|
::
|
||||||
:: scry and subscription paths:
|
:: scry and subscription paths:
|
||||||
::
|
::
|
||||||
:: /local-pages/[some-group] all pages we saved by recency
|
:: (map path pages) %local-pages
|
||||||
:: /submissions/[some-group] all submissions by recency
|
:: /local-pages our saved pages
|
||||||
|
:: /local-pages/some-path our saved pages on path
|
||||||
::
|
::
|
||||||
/+ *link, default-agent, verb
|
:: (map path submissions) %submissions
|
||||||
|
:: /submissions all submissions we've seen
|
||||||
|
:: /submissions/some-path all submissions we've seen on path
|
||||||
|
::
|
||||||
|
:: (map path (map url notes)) %annotations
|
||||||
|
:: /annotations our comments
|
||||||
|
:: /annotations/wood-url our comments on url
|
||||||
|
:: /annotations/wood-url/some-path our comments on url on path
|
||||||
|
:: /annotations//some-path our comments on path
|
||||||
|
::
|
||||||
|
:: (map path (map url comments)) %discussions
|
||||||
|
:: /discussions all comments
|
||||||
|
:: /discussions/wood-url all comments on url
|
||||||
|
:: /discussions/wood-url/some-path all comments on url on path
|
||||||
|
:: /discussions//some-path all comments on path
|
||||||
|
::
|
||||||
|
:: subscription-only paths:
|
||||||
|
::
|
||||||
|
:: [path url] %observation
|
||||||
|
:: /seen updates whenever an item is seen
|
||||||
|
::
|
||||||
|
:: scry-only paths:
|
||||||
|
::
|
||||||
|
::
|
||||||
|
:: (map path (set url))
|
||||||
|
:: /unseen the ones we haven't seen yet
|
||||||
|
::
|
||||||
|
:: (set url)
|
||||||
|
:: /unseen/some-path the ones we haven't seen here yet
|
||||||
|
::
|
||||||
|
:: ?
|
||||||
|
:: /seen/wood-url/some-path have we seen this here
|
||||||
|
::
|
||||||
|
/+ *link, default-agent, verb, dbug
|
||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ state-0
|
+$ state-0
|
||||||
$: %0
|
$: %0
|
||||||
by-group=(map path links)
|
by-group=(map path links)
|
||||||
by-site=(map site (list [path submission]))
|
by-site=(map site (list [path submission]))
|
||||||
|
discussions=(per-path-url discussion)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ links
|
+$ links
|
||||||
$: ::NOTE all lists by recency
|
$: ::NOTE all lists by recency
|
||||||
=submissions
|
=submissions
|
||||||
ours=pages
|
ours=pages
|
||||||
|
seen=(set url)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ discussion
|
||||||
|
$: =comments
|
||||||
|
ours=notes
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
@ -31,6 +78,7 @@
|
|||||||
=| state-0
|
=| state-0
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
|
%- agent:dbug
|
||||||
%+ verb |
|
%+ verb |
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
@ -64,12 +112,58 @@
|
|||||||
?+ path (on-peek:def path)
|
?+ path (on-peek:def path)
|
||||||
[%y ?(%local-pages %submissions) ~]
|
[%y ?(%local-pages %submissions) ~]
|
||||||
``noun+!>(~(key by by-group))
|
``noun+!>(~(key by by-group))
|
||||||
::
|
::
|
||||||
[%x %local-pages ^]
|
[%x %local-pages *]
|
||||||
``noun+!>((get-local-pages:do t.t.path))
|
``noun+!>((get-local-pages:do t.t.path))
|
||||||
::
|
::
|
||||||
[%x %submissions ^]
|
[%x %submissions *]
|
||||||
``noun+!>((get-submissions:do t.t.path))
|
``noun+!>((get-submissions:do t.t.path))
|
||||||
|
::
|
||||||
|
[%y ?(%annotations %discussions) *]
|
||||||
|
=/ [spath=^path surl=url]
|
||||||
|
(break-discussion-path t.t.path)
|
||||||
|
=- ``noun+!>(-)
|
||||||
|
::
|
||||||
|
?: =(~ surl)
|
||||||
|
:: no url, provide urls that have comments
|
||||||
|
::
|
||||||
|
^- (set url)
|
||||||
|
?~ spath
|
||||||
|
:: no path, find urls accross all paths
|
||||||
|
::
|
||||||
|
%- ~(rep by discussions)
|
||||||
|
|= [[* discussions=(map url discussion)] urls=(set url)]
|
||||||
|
%- ~(uni in urls)
|
||||||
|
~(key by discussions)
|
||||||
|
:: specified path, find urls for that specific path
|
||||||
|
::
|
||||||
|
%~ key by
|
||||||
|
(~(gut by discussions) spath *(map url *))
|
||||||
|
:: specified url and path, nothing to list here
|
||||||
|
::
|
||||||
|
?^ spath !!
|
||||||
|
:: no path, find paths with comments for this url
|
||||||
|
::
|
||||||
|
^- (set ^path)
|
||||||
|
%- ~(rep by discussions)
|
||||||
|
|= [[=^path urls=(map url discussion)] paths=(set ^path)]
|
||||||
|
?. (~(has by urls) surl) paths
|
||||||
|
(~(put in paths) path)
|
||||||
|
::
|
||||||
|
[%x %annotations *]
|
||||||
|
``noun+!>((get-annotations:do t.t.path))
|
||||||
|
::
|
||||||
|
[%x %discussions *]
|
||||||
|
``noun+!>((get-discussions:do t.t.path))
|
||||||
|
::
|
||||||
|
[%x %seen @ ^]
|
||||||
|
``noun+!>((is-seen:do t.t.path))
|
||||||
|
::
|
||||||
|
[%x %unseen ~]
|
||||||
|
``noun+!>(get-all-unseen:do)
|
||||||
|
::
|
||||||
|
[%x %unseen ^]
|
||||||
|
``noun+!>((get-unseen:do t.t.path))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
@ -78,19 +172,39 @@
|
|||||||
?> (team:title [our src]:bowl) ::TODO /lib/store
|
?> (team:title [our src]:bowl) ::TODO /lib/store
|
||||||
:_ this
|
:_ this
|
||||||
|^ ?+ path (on-watch:def path)
|
|^ ?+ path (on-watch:def path)
|
||||||
[%local-pages ^]
|
[%local-pages *]
|
||||||
%+ give %link-update
|
%+ give %link-initial
|
||||||
[%local-pages t.path (get-local-pages:do t.path)]
|
^- initial
|
||||||
|
[%local-pages (get-local-pages:do t.path)]
|
||||||
::
|
::
|
||||||
[%submissions ^]
|
[%submissions *]
|
||||||
%+ give %link-update
|
%+ give %link-initial
|
||||||
[%submissions t.path (get-submissions:do t.path)]
|
^- initial
|
||||||
|
[%submissions (get-submissions:do t.path)]
|
||||||
|
::
|
||||||
|
[%annotations *]
|
||||||
|
%+ give %link-initial
|
||||||
|
^- initial
|
||||||
|
[%annotations (get-annotations:do t.path)]
|
||||||
|
::
|
||||||
|
[%discussions *]
|
||||||
|
%+ give %link-initial
|
||||||
|
^- initial
|
||||||
|
[%discussions (get-discussions:do t.path)]
|
||||||
|
::
|
||||||
|
[%seen ~]
|
||||||
|
~
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ give
|
++ give
|
||||||
|* [=mark =noun]
|
|* [=mark =noun]
|
||||||
^- (list card)
|
^- (list card)
|
||||||
[%give %fact ~ mark !>(noun)]~
|
[%give %fact ~ mark !>(noun)]~
|
||||||
|
::
|
||||||
|
++ give-single
|
||||||
|
|* [=mark =noun]
|
||||||
|
^- card
|
||||||
|
[%give %fact ~ mark !>(noun)]
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
@ -107,15 +221,19 @@
|
|||||||
|= =action
|
|= =action
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?- -.action
|
?- -.action
|
||||||
%add (add-page +.action)
|
%save (save-page +.action)
|
||||||
|
%note (note-note +.action)
|
||||||
|
%seen (seen-submission +.action)
|
||||||
|
::
|
||||||
%hear (hear-submission +.action)
|
%hear (hear-submission +.action)
|
||||||
|
%read (read-comment +.action)
|
||||||
==
|
==
|
||||||
:: +add-page: save a page ourselves
|
:: +save-page: save a page ourselves
|
||||||
::
|
::
|
||||||
++ add-page
|
++ save-page
|
||||||
|= [=path title=@t =url]
|
|= [=path title=@t =url]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
?< =(~ path)
|
?< |(=(~ path) =(~ title) =(~ url))
|
||||||
:: add page to group ours
|
:: add page to group ours
|
||||||
::
|
::
|
||||||
=/ =links (~(gut by by-group) path *links)
|
=/ =links (~(gut by by-group) path *links)
|
||||||
@ -124,16 +242,75 @@
|
|||||||
=. by-group (~(put by by-group) path links)
|
=. by-group (~(put by by-group) path links)
|
||||||
:: do generic submission logic
|
:: do generic submission logic
|
||||||
::
|
::
|
||||||
=^ cards state
|
=^ submission-cards state
|
||||||
(hear-submission path [our.bowl page])
|
(hear-submission path [our.bowl page])
|
||||||
|
:: mark page as seen (because we submitted it ourselves)
|
||||||
|
::
|
||||||
|
=^ seen-cards state
|
||||||
|
(seen-submission path `url)
|
||||||
:: send updates to subscribers
|
:: send updates to subscribers
|
||||||
::
|
::
|
||||||
:_ state
|
:_ state
|
||||||
:_ cards
|
:_ (weld submission-cards seen-cards)
|
||||||
:+ %give %fact
|
:+ %give %fact
|
||||||
:+ [%local-pages path]~
|
:+ :~ /local-pages
|
||||||
|
[%local-pages path]
|
||||||
|
==
|
||||||
%link-update
|
%link-update
|
||||||
!>([%local-pages path [page]~])
|
!>([%local-pages path [page]~])
|
||||||
|
:: +note-note: save a note for a url
|
||||||
|
::
|
||||||
|
++ note-note
|
||||||
|
|= [=path =url udon=@t]
|
||||||
|
^- (quip card _state)
|
||||||
|
?< |(=(~ path) =(~ url) =(~ udon))
|
||||||
|
:: add note to discussion ours
|
||||||
|
::
|
||||||
|
=/ urls (~(gut by discussions) path *(map ^url discussion))
|
||||||
|
=/ =discussion (~(gut by urls) url *discussion)
|
||||||
|
=/ =note [now.bowl udon]
|
||||||
|
=. ours.discussion [note ours.discussion]
|
||||||
|
=. urls (~(put by urls) url discussion)
|
||||||
|
=. discussions (~(put by discussions) path urls)
|
||||||
|
:: do generic comment logic
|
||||||
|
::
|
||||||
|
=^ cards state
|
||||||
|
(read-comment path url [our.bowl note])
|
||||||
|
:: send updates to subscribers
|
||||||
|
::
|
||||||
|
:_ state
|
||||||
|
^- (list card)
|
||||||
|
:_ cards
|
||||||
|
:+ %give %fact
|
||||||
|
:+ :~ /annotations
|
||||||
|
[%annotations %$ path]
|
||||||
|
[%annotations (build-discussion-path url)]
|
||||||
|
[%annotations (build-discussion-path path url)]
|
||||||
|
==
|
||||||
|
%link-update
|
||||||
|
!>([%annotations path url [note]~])
|
||||||
|
:: +seen-submission: mark url as seen/read
|
||||||
|
::
|
||||||
|
:: if no url specified, all under path are marked as read
|
||||||
|
::
|
||||||
|
++ seen-submission
|
||||||
|
|= [=path murl=(unit url)]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ =links (~(gut by by-group) path *links)
|
||||||
|
:: new: urls we want to, but haven't yet, marked as seen
|
||||||
|
::
|
||||||
|
=/ new=(set url)
|
||||||
|
%. seen.links
|
||||||
|
%~ dif in
|
||||||
|
^- (set url)
|
||||||
|
?^ murl (sy ~[u.murl])
|
||||||
|
%- ~(gas in *(set url))
|
||||||
|
%+ turn submissions.links
|
||||||
|
|=(submission url)
|
||||||
|
?: =(~ new) [~ state]
|
||||||
|
=. seen.links (~(uni in seen.links) new)
|
||||||
|
:_ state(by-group (~(put by by-group) path links))
|
||||||
|
[%give %fact ~[/seen] %link-update !>([%observation path new])]~
|
||||||
:: +hear-submission: record page someone else saved
|
:: +hear-submission: record page someone else saved
|
||||||
::
|
::
|
||||||
++ hear-submission
|
++ hear-submission
|
||||||
@ -143,7 +320,11 @@
|
|||||||
:: add link to group submissions
|
:: add link to group submissions
|
||||||
::
|
::
|
||||||
=/ =links (~(gut by by-group) path *links)
|
=/ =links (~(gut by by-group) path *links)
|
||||||
=. submissions.links [submission submissions.links]
|
=^ added submissions.links
|
||||||
|
?: ?=(^ (find ~[submission] submissions.links))
|
||||||
|
[| submissions.links]
|
||||||
|
:- &
|
||||||
|
(submissions:merge submissions.links ~[submission])
|
||||||
=. by-group (~(put by by-group) path links)
|
=. by-group (~(put by by-group) path links)
|
||||||
:: add submission to global sites
|
:: add submission to global sites
|
||||||
::
|
::
|
||||||
@ -152,21 +333,156 @@
|
|||||||
:: send updates to subscribers
|
:: send updates to subscribers
|
||||||
::
|
::
|
||||||
:_ state
|
:_ state
|
||||||
|
?. added ~
|
||||||
:_ ~
|
:_ ~
|
||||||
:+ %give %fact
|
:+ %give %fact
|
||||||
:+ [%submissions path]~
|
:+ :~ /submissions
|
||||||
|
[%submissions path]
|
||||||
|
==
|
||||||
%link-update
|
%link-update
|
||||||
!>([%submissions path [submission]~])
|
!>([%submissions path [submission]~])
|
||||||
|
:: +read-comment: record a comment someone else made
|
||||||
|
::
|
||||||
|
++ read-comment
|
||||||
|
|= [=path =url =comment]
|
||||||
|
^- (quip card _state)
|
||||||
|
:: add comment to url's discussion
|
||||||
|
::
|
||||||
|
=/ urls (~(gut by discussions) path *(map ^url discussion))
|
||||||
|
=/ =discussion (~(gut by urls) url *discussion)
|
||||||
|
=^ added comments.discussion
|
||||||
|
?: ?=(^ (find ~[comment] comments.discussion))
|
||||||
|
[| comments.discussion]
|
||||||
|
:- &
|
||||||
|
(comments:merge comments.discussion ~[comment])
|
||||||
|
=. urls (~(put by urls) url discussion)
|
||||||
|
=. discussions (~(put by discussions) path urls)
|
||||||
|
:: send updates to subscribers
|
||||||
|
::
|
||||||
|
:_ state
|
||||||
|
?. added ~
|
||||||
|
:_ ~
|
||||||
|
:+ %give %fact
|
||||||
|
:+ :~ /discussions
|
||||||
|
[%discussions '' path]
|
||||||
|
[%discussions (build-discussion-path url)]
|
||||||
|
[%discussions (build-discussion-path path url)]
|
||||||
|
==
|
||||||
|
%link-update
|
||||||
|
!>([%discussions path url [comment]~])
|
||||||
::
|
::
|
||||||
:: reading
|
:: reading
|
||||||
::
|
::
|
||||||
++ get-local-pages
|
++ get-local-pages
|
||||||
|= =path
|
|= =path
|
||||||
^- pages
|
^- (map ^path pages)
|
||||||
|
?~ path
|
||||||
|
:: all paths
|
||||||
|
::
|
||||||
|
%- ~(run by by-group)
|
||||||
|
|=(links ours)
|
||||||
|
:: specific path
|
||||||
|
::
|
||||||
|
%+ ~(put by *(map ^path pages)) path
|
||||||
ours:(~(gut by by-group) path *links)
|
ours:(~(gut by by-group) path *links)
|
||||||
::
|
::
|
||||||
++ get-submissions
|
++ get-submissions
|
||||||
|= =path
|
|= =path
|
||||||
^- submissions
|
^- (map ^path submissions)
|
||||||
|
?~ path
|
||||||
|
:: all paths
|
||||||
|
::
|
||||||
|
%- ~(run by by-group)
|
||||||
|
|=(links submissions)
|
||||||
|
:: specific path
|
||||||
|
::
|
||||||
|
%+ ~(put by *(map ^path submissions)) path
|
||||||
submissions:(~(gut by by-group) path *links)
|
submissions:(~(gut by by-group) path *links)
|
||||||
|
::
|
||||||
|
++ get-all-unseen
|
||||||
|
^- (jug path url)
|
||||||
|
%- ~(rut by by-group)
|
||||||
|
|= [=path *]
|
||||||
|
(get-unseen path)
|
||||||
|
::
|
||||||
|
++ get-unseen
|
||||||
|
|= =path
|
||||||
|
^- (set url)
|
||||||
|
=/ =links
|
||||||
|
(~(gut by by-group) path *links)
|
||||||
|
%- ~(gas in *(set url))
|
||||||
|
%+ murn submissions.links
|
||||||
|
|= submission
|
||||||
|
?: (~(has in seen.links) url) ~
|
||||||
|
(some url)
|
||||||
|
::
|
||||||
|
++ is-seen
|
||||||
|
|= =path
|
||||||
|
^- ?
|
||||||
|
=/ [=^path =url]
|
||||||
|
(break-discussion-path path)
|
||||||
|
%. url
|
||||||
|
%~ has in
|
||||||
|
seen:(~(gut by by-group) path *links)
|
||||||
|
::
|
||||||
|
::
|
||||||
|
++ get-annotations
|
||||||
|
|= =path
|
||||||
|
^- (per-path-url notes)
|
||||||
|
=/ args=[=^path =url]
|
||||||
|
(break-discussion-path path)
|
||||||
|
|^ ?~ path
|
||||||
|
:: all paths
|
||||||
|
::
|
||||||
|
(~(run by discussions) get-ours)
|
||||||
|
:: specific path
|
||||||
|
::
|
||||||
|
%+ ~(put by *(per-path-url notes)) path.args
|
||||||
|
%- get-ours
|
||||||
|
%+ ~(gut by discussions) path.args
|
||||||
|
*(map url discussion)
|
||||||
|
::
|
||||||
|
++ get-ours
|
||||||
|
|= m=(map url discussion)
|
||||||
|
^- (map url notes)
|
||||||
|
?: =(~ url.args)
|
||||||
|
:: all urls
|
||||||
|
::
|
||||||
|
%- ~(run by m)
|
||||||
|
|=(discussion ours)
|
||||||
|
:: specific url
|
||||||
|
::
|
||||||
|
%+ ~(put by *(map url notes)) url.args
|
||||||
|
ours:(~(gut by m) url.args *discussion)
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ get-discussions
|
||||||
|
|= =path
|
||||||
|
^- (per-path-url comments)
|
||||||
|
=/ args=[=^path =url]
|
||||||
|
(break-discussion-path path)
|
||||||
|
|^ ?~ path
|
||||||
|
:: all paths
|
||||||
|
::
|
||||||
|
(~(run by discussions) get-comments)
|
||||||
|
:: specific path
|
||||||
|
::
|
||||||
|
%+ ~(put by *(per-path-url comments)) path.args
|
||||||
|
%- get-comments
|
||||||
|
%+ ~(gut by discussions) path.args
|
||||||
|
*(map url discussion)
|
||||||
|
::
|
||||||
|
++ get-comments
|
||||||
|
|= m=(map url discussion)
|
||||||
|
^- (map url comments)
|
||||||
|
?: =(~ url.args)
|
||||||
|
:: all urls
|
||||||
|
::
|
||||||
|
%- ~(run by m)
|
||||||
|
|=(discussion comments)
|
||||||
|
:: specific url
|
||||||
|
::
|
||||||
|
%+ ~(put by *(map url comments)) url.args
|
||||||
|
comments:(~(gut by m) url.args *discussion)
|
||||||
|
--
|
||||||
--
|
--
|
||||||
|
634
pkg/arvo/app/link-view.hoon
Normal file
@ -0,0 +1,634 @@
|
|||||||
|
:: link-view: frontend endpoints
|
||||||
|
::
|
||||||
|
:: endpoints, mapping onto link-store's paths. p is for page as in pagination.
|
||||||
|
:: only the /0/submissions endpoint provides updates.
|
||||||
|
:: as with link-store, urls are expected to use +wood encoding.
|
||||||
|
::
|
||||||
|
:: /json/0/submissions initial + updates for all
|
||||||
|
:: /json/[p]/submissions/[collection] page for one collection
|
||||||
|
:: /json/[p]/discussions/[wood-url]/[collection] page for url in collection
|
||||||
|
:: /json/[n]/submission/[wood-url]/[collection] nth matching submission
|
||||||
|
:: /json/seen mark-as-read updates
|
||||||
|
::
|
||||||
|
/- *link-view,
|
||||||
|
*invite-store, group-store,
|
||||||
|
link-listen-hook,
|
||||||
|
group-hook, permission-hook, permission-group-hook,
|
||||||
|
metadata-hook, contact-view
|
||||||
|
/+ *link, metadata, *server, default-agent, verb, dbug
|
||||||
|
~% %link-view-top ..is ~
|
||||||
|
::
|
||||||
|
|%
|
||||||
|
+$ state-0
|
||||||
|
$: %0
|
||||||
|
~
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ card card:agent:gall
|
||||||
|
--
|
||||||
|
::
|
||||||
|
=| state-0
|
||||||
|
=* state -
|
||||||
|
::
|
||||||
|
%+ verb |
|
||||||
|
%- agent:dbug
|
||||||
|
^- agent:gall
|
||||||
|
=<
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* this .
|
||||||
|
do ~(. +> bowl)
|
||||||
|
def ~(. (default-agent this %|) bowl)
|
||||||
|
::
|
||||||
|
++ on-init
|
||||||
|
^- (quip card _this)
|
||||||
|
:_ this
|
||||||
|
:~ [%pass /connect %arvo %e %connect [~ /'~link'] dap.bowl]
|
||||||
|
[%pass /submissions %agent [our.bowl %link-store] %watch /submissions]
|
||||||
|
[%pass /discussions %agent [our.bowl %link-store] %watch /discussions]
|
||||||
|
[%pass /seen %agent [our.bowl %link-store] %watch /seen]
|
||||||
|
::
|
||||||
|
=+ [%add dap.bowl /tile '/~link/js/tile.js']
|
||||||
|
[%pass /launch %agent [our.bowl %launch] %poke %launch-action !>(-)]
|
||||||
|
::
|
||||||
|
=+ [%invite-action !>([%create /link])]
|
||||||
|
[%pass /invitatory/create %agent [our.bowl %invite-store] %poke -]
|
||||||
|
::
|
||||||
|
=+ /invitatory/link
|
||||||
|
[%pass - %agent [our.bowl %invite-store] %watch -]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ 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)
|
||||||
|
:_ this
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
%handle-http-request
|
||||||
|
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
|
||||||
|
%+ give-simple-payload:app eyre-id
|
||||||
|
%+ require-authorization:app inbound-request
|
||||||
|
handle-http-request:do
|
||||||
|
::
|
||||||
|
%link-action
|
||||||
|
[(handle-action:do !<(action vase)) ~]
|
||||||
|
::
|
||||||
|
%link-view-action
|
||||||
|
(handle-view-action:do !<(view-action vase))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?: ?| ?=([%http-response *] path)
|
||||||
|
?=([%json %seen ~] path)
|
||||||
|
==
|
||||||
|
[~ this]
|
||||||
|
?: ?=([%tile ~] path)
|
||||||
|
:_ this
|
||||||
|
~[give-tile-data:do]
|
||||||
|
?. ?=([%json @ @ *] path)
|
||||||
|
(on-watch:def path)
|
||||||
|
=/ p=@ud (slav %ud i.t.path)
|
||||||
|
?+ t.t.path (on-watch:def path)
|
||||||
|
[%submissions ~]
|
||||||
|
:_ this
|
||||||
|
(give-initial-submissions:do p ~)
|
||||||
|
::
|
||||||
|
[%submissions ^]
|
||||||
|
:_ this
|
||||||
|
(give-initial-submissions:do p t.t.t.path)
|
||||||
|
::
|
||||||
|
[%submission @ ^]
|
||||||
|
:_ this
|
||||||
|
(give-specific-submission:do p (break-discussion-path t.t.t.path))
|
||||||
|
::
|
||||||
|
[%discussions @ ^]
|
||||||
|
:_ this
|
||||||
|
(give-initial-discussions:do p (break-discussion-path t.t.t.path))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-agent
|
||||||
|
|= [=wire =sign:agent:gall]
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ -.sign (on-agent:def wire sign)
|
||||||
|
%kick
|
||||||
|
:_ this
|
||||||
|
=/ app=term
|
||||||
|
?: ?=([%invites *] wire)
|
||||||
|
%invite-store
|
||||||
|
%link-store
|
||||||
|
[%pass wire %agent [our.bowl app] %watch wire]~
|
||||||
|
::
|
||||||
|
%fact
|
||||||
|
=* mark p.cage.sign
|
||||||
|
=* vase q.cage.sign
|
||||||
|
?+ mark (on-agent:def wire sign)
|
||||||
|
%invite-update [(handle-invite-update:do !<(invite-update vase)) this]
|
||||||
|
%link-initial [~ this]
|
||||||
|
::
|
||||||
|
%link-update
|
||||||
|
:_ this
|
||||||
|
:- (send-update:do !<(update vase))
|
||||||
|
?: =(/discussions wire) ~
|
||||||
|
~[give-tile-data:do]
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-arvo
|
||||||
|
|= [=wire =sign-arvo]
|
||||||
|
^- (quip card _this)
|
||||||
|
?. ?=([%e %bound *] sign-arvo)
|
||||||
|
(on-arvo:def wire sign-arvo)
|
||||||
|
~? !accepted.sign-arvo
|
||||||
|
[dap.bowl "bind rejected!" binding.sign-arvo]
|
||||||
|
[~ this]
|
||||||
|
::
|
||||||
|
++ on-peek on-peek:def
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
||||||
|
::
|
||||||
|
~% %link-view-logic ..card ~
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* md ~(. metadata bowl)
|
||||||
|
::
|
||||||
|
++ page-size 25
|
||||||
|
++ get-paginated
|
||||||
|
|* [page=(unit @ud) list=(list)]
|
||||||
|
^- [total=@ud pages=@ud page=_list]
|
||||||
|
=/ l=@ud (lent list)
|
||||||
|
:+ l
|
||||||
|
%+ add (div l page-size)
|
||||||
|
(min 1 (mod l page-size))
|
||||||
|
?~ page list
|
||||||
|
%+ swag
|
||||||
|
[(mul u.page page-size) page-size]
|
||||||
|
list
|
||||||
|
::
|
||||||
|
++ page-to-json
|
||||||
|
=, enjs:format
|
||||||
|
|* $: page-number=@ud
|
||||||
|
[total-items=@ud total-pages=@ud page=(list)]
|
||||||
|
item-to-json=$-(* json)
|
||||||
|
==
|
||||||
|
^- json
|
||||||
|
%- pairs
|
||||||
|
:~ 'totalItems'^(numb total-items)
|
||||||
|
'totalPages'^(numb total-pages)
|
||||||
|
'pageNumber'^(numb page-number)
|
||||||
|
'page'^a+(turn page item-to-json)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-http-request
|
||||||
|
|= =inbound-request:eyre
|
||||||
|
^- simple-payload:http
|
||||||
|
?. =(src.bowl our.bowl)
|
||||||
|
[[403 ~] ~]
|
||||||
|
:: request-line: parsed url + params
|
||||||
|
::
|
||||||
|
=/ =request-line
|
||||||
|
%- parse-request-line
|
||||||
|
url.request.inbound-request
|
||||||
|
=* req-head header-list.request.inbound-request
|
||||||
|
?+ method.request.inbound-request not-found:gen
|
||||||
|
%'GET'
|
||||||
|
(handle-get req-head request-line)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-get
|
||||||
|
|= [request-headers=header-list:http =request-line]
|
||||||
|
^- simple-payload:http
|
||||||
|
:: try to load file from clay
|
||||||
|
::
|
||||||
|
?~ ext.request-line
|
||||||
|
:: for extension-less requests, always just serve the index.html.
|
||||||
|
:: that way the js can load and figure out how to deal with that route.
|
||||||
|
::
|
||||||
|
$(request-line [[`%html ~[%'~link' 'index']] args.request-line])
|
||||||
|
=/ file=(unit octs)
|
||||||
|
?. ?=([%'~link' *] site.request-line) ~
|
||||||
|
(get-file-at /app/link [t.site u.ext]:request-line)
|
||||||
|
?~ file not-found:gen
|
||||||
|
?+ u.ext.request-line not-found:gen
|
||||||
|
%html (html-response:gen u.file)
|
||||||
|
%js (js-response:gen u.file)
|
||||||
|
%css (css-response:gen u.file)
|
||||||
|
%png (png-response:gen u.file)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ get-file-at
|
||||||
|
|= [base=path file=path ext=@ta]
|
||||||
|
^- (unit octs)
|
||||||
|
:: only expose html, css and js files for now
|
||||||
|
::
|
||||||
|
?. ?=(?(%html %css %js %png) ext)
|
||||||
|
~
|
||||||
|
=/ =path
|
||||||
|
:* (scot %p our.bowl)
|
||||||
|
q.byk.bowl
|
||||||
|
(scot %da now.bowl)
|
||||||
|
(snoc (weld base file) ext)
|
||||||
|
==
|
||||||
|
?. .^(? %cu path)
|
||||||
|
~
|
||||||
|
%- some
|
||||||
|
%- as-octs:mimes:html
|
||||||
|
.^(@ %cx path)
|
||||||
|
::
|
||||||
|
++ do-poke
|
||||||
|
|= [app=term =mark =vase]
|
||||||
|
^- card
|
||||||
|
[%pass /create/[app]/[mark] %agent [our.bowl app] %poke mark vase]
|
||||||
|
::
|
||||||
|
++ handle-invite-update
|
||||||
|
|= upd=invite-update
|
||||||
|
^- (list card)
|
||||||
|
?. ?=(%accepted -.upd) ~
|
||||||
|
?. =(/link path.upd) ~
|
||||||
|
:~ :: sync the group
|
||||||
|
::
|
||||||
|
%^ do-poke %group-hook
|
||||||
|
%group-hook-action
|
||||||
|
!> ^- group-hook-action:group-hook
|
||||||
|
[%add ship path]:invite.upd
|
||||||
|
::
|
||||||
|
:: sync the metadata
|
||||||
|
::
|
||||||
|
%^ do-poke %metadata-hook
|
||||||
|
%metadata-hook-action
|
||||||
|
!> ^- metadata-hook-action:metadata-hook
|
||||||
|
[%add-synced ship path]:invite.upd
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-action
|
||||||
|
|= =action
|
||||||
|
^- card
|
||||||
|
[%pass /action %agent [our.bowl %link-store] %poke %link-action !>(action)]
|
||||||
|
::
|
||||||
|
++ handle-view-action
|
||||||
|
|= act=view-action
|
||||||
|
^- (list card)
|
||||||
|
?- -.act
|
||||||
|
%create (handle-create +.act)
|
||||||
|
%delete (handle-delete +.act)
|
||||||
|
%invite (handle-invite +.act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-create
|
||||||
|
|= [=path title=@t description=@t members=create-members real-group=?]
|
||||||
|
^- (list card)
|
||||||
|
=/ group-path=^path
|
||||||
|
?- -.members
|
||||||
|
%group path.members
|
||||||
|
::
|
||||||
|
%ships
|
||||||
|
%+ weld
|
||||||
|
?:(real-group ~ [~.~]~)
|
||||||
|
[(scot %p our.bowl) path]
|
||||||
|
==
|
||||||
|
=; group-setup=(list card)
|
||||||
|
%+ weld group-setup
|
||||||
|
:~ :: add collection to metadata-store
|
||||||
|
::
|
||||||
|
%^ do-poke %metadata-hook
|
||||||
|
%metadata-action
|
||||||
|
!> ^- metadata-action:md
|
||||||
|
:^ %add group-path
|
||||||
|
[%link path]
|
||||||
|
%* . *metadata:md
|
||||||
|
title title
|
||||||
|
description description
|
||||||
|
date-created now.bowl
|
||||||
|
creator our.bowl
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: expose the metadata
|
||||||
|
::
|
||||||
|
%^ do-poke %metadata-hook
|
||||||
|
%metadata-hook-action
|
||||||
|
!> ^- metadata-hook-action:metadata-hook
|
||||||
|
[%add-owned group-path]
|
||||||
|
::
|
||||||
|
:: watch the collection ourselves
|
||||||
|
::
|
||||||
|
%^ do-poke %link-listen-hook
|
||||||
|
%link-listen-action
|
||||||
|
!> ^- action:link-listen-hook
|
||||||
|
[%watch path]
|
||||||
|
==
|
||||||
|
?: ?=(%group -.members) ~
|
||||||
|
:: if the group is "real", make contact-view do the heavy lifting
|
||||||
|
::
|
||||||
|
?: real-group
|
||||||
|
:_ ~
|
||||||
|
%^ do-poke %contact-view
|
||||||
|
%contact-view-action
|
||||||
|
!> ^- contact-view-action:contact-view
|
||||||
|
[%create group-path ships.members title description]
|
||||||
|
:: for "unmanaged" groups, do it ourselves
|
||||||
|
::
|
||||||
|
:* :: create the new group
|
||||||
|
::
|
||||||
|
%^ do-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action:group-store
|
||||||
|
[%bundle group-path]
|
||||||
|
::
|
||||||
|
:: fill the new group
|
||||||
|
::
|
||||||
|
%^ do-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action:group-store
|
||||||
|
[%add (~(put in ships.members) our.bowl) group-path]
|
||||||
|
::
|
||||||
|
:: make group available
|
||||||
|
::
|
||||||
|
%^ do-poke %group-hook
|
||||||
|
%group-hook-action
|
||||||
|
!> ^- group-hook-action:group-hook
|
||||||
|
[%add our.bowl group-path]
|
||||||
|
::
|
||||||
|
:: mirror group into a permission
|
||||||
|
::
|
||||||
|
%^ do-poke %permission-group-hook
|
||||||
|
%permission-group-hook-action
|
||||||
|
!> ^- permission-group-hook-action:permission-group-hook
|
||||||
|
[%associate group-path [group-path^%white ~ ~]]
|
||||||
|
::
|
||||||
|
:: expose the permission
|
||||||
|
::
|
||||||
|
%^ do-poke %permission-hook
|
||||||
|
%permission-hook-action
|
||||||
|
!> ^- permission-hook-action:permission-hook
|
||||||
|
[%add-owned group-path group-path]
|
||||||
|
::
|
||||||
|
:: send invites
|
||||||
|
::
|
||||||
|
%+ turn ~(tap in ships.members)
|
||||||
|
|= =ship
|
||||||
|
^- card
|
||||||
|
%^ do-poke %invite-hook
|
||||||
|
%invite-action
|
||||||
|
!> ^- invite-action
|
||||||
|
:^ %invite /link
|
||||||
|
(sham group-path eny.bowl)
|
||||||
|
:* our.bowl
|
||||||
|
%group-hook
|
||||||
|
group-path
|
||||||
|
ship
|
||||||
|
title
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-delete
|
||||||
|
|= =path
|
||||||
|
^- (list card)
|
||||||
|
=/ groups=(list ^path)
|
||||||
|
(groups-from-resource:md [%link path])
|
||||||
|
%- zing
|
||||||
|
%+ turn groups
|
||||||
|
|= =group=^path
|
||||||
|
%+ snoc
|
||||||
|
^- (list card)
|
||||||
|
:: if it's a real group, we can't/shouldn't unsync it. this leaves us with
|
||||||
|
:: no way to stop propagation of collection deletion.
|
||||||
|
::
|
||||||
|
?. ?=([%'~' ^] group-path) ~
|
||||||
|
:: if it's an unmanaged group, we just stop syncing the group & metadata,
|
||||||
|
:: and clean up the group (after un-hooking it, to not push deletion).
|
||||||
|
::
|
||||||
|
:~ %^ do-poke %group-hook
|
||||||
|
%group-hook-action
|
||||||
|
!> ^- group-hook-action:group-hook
|
||||||
|
[%remove group-path]
|
||||||
|
::
|
||||||
|
%^ do-poke %metadata-hook
|
||||||
|
%metadata-hook-action
|
||||||
|
!> ^- metadata-hook-action:metadata-hook
|
||||||
|
[%remove group-path]
|
||||||
|
::
|
||||||
|
%^ do-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action:group-store
|
||||||
|
[%unbundle group-path]
|
||||||
|
==
|
||||||
|
:: remove collection from metadata-store
|
||||||
|
::
|
||||||
|
%^ do-poke %metadata-store
|
||||||
|
%metadata-action
|
||||||
|
!> ^- metadata-action:md
|
||||||
|
[%remove group-path [%link path]]
|
||||||
|
::
|
||||||
|
++ handle-invite
|
||||||
|
|= [=path ships=(set ship)]
|
||||||
|
^- (list card)
|
||||||
|
%- zing
|
||||||
|
%+ turn (groups-from-resource:md %link path)
|
||||||
|
|= =group=^path
|
||||||
|
^- (list card)
|
||||||
|
:- %^ do-poke %group-store
|
||||||
|
%group-action
|
||||||
|
!> ^- group-action:group-store
|
||||||
|
[%add ships group-path]
|
||||||
|
:: for managed groups, rely purely on group logic for invites
|
||||||
|
::
|
||||||
|
?. ?=([%'~' ^] group-path)
|
||||||
|
~
|
||||||
|
:: for unmanaged groups, send invites manually
|
||||||
|
::
|
||||||
|
%+ turn ~(tap in ships)
|
||||||
|
|= =ship
|
||||||
|
^- card
|
||||||
|
%^ do-poke %invite-hook
|
||||||
|
%invite-action
|
||||||
|
!> ^- invite-action
|
||||||
|
:^ %invite /link
|
||||||
|
(sham group-path eny.bowl)
|
||||||
|
:* our.bowl
|
||||||
|
%group-hook
|
||||||
|
group-path
|
||||||
|
ship
|
||||||
|
(rsh 3 1 (spat path))
|
||||||
|
==
|
||||||
|
:: +give-tile-data: total unread count as json object
|
||||||
|
::
|
||||||
|
::NOTE the full recalc of totals here probably isn't the end of the world.
|
||||||
|
:: but in case it is, well, here it is.
|
||||||
|
::
|
||||||
|
++ give-tile-data
|
||||||
|
^- card
|
||||||
|
=; =json
|
||||||
|
[%give %fact ~[/tile] %json !>(json)]
|
||||||
|
%+ frond:enjs:format 'unseen'
|
||||||
|
%- numb:enjs:format
|
||||||
|
%- %~ rep in
|
||||||
|
(scry-for (jug path url) /unseen)
|
||||||
|
|= [[=path unseen=(set url)] total=@ud]
|
||||||
|
%+ add total
|
||||||
|
~(wyt in unseen)
|
||||||
|
::
|
||||||
|
:: +give-initial-submissions: page of submissions on path
|
||||||
|
::
|
||||||
|
:: for the / path, give page for every path
|
||||||
|
::
|
||||||
|
:: result is in the shape of: {
|
||||||
|
:: "/some/path": {
|
||||||
|
:: totalItems: 1,
|
||||||
|
:: totalPages: 1,
|
||||||
|
:: pageNumber: 0,
|
||||||
|
:: page: [
|
||||||
|
:: { commentCount: 1, ...restOfTheSubmission }
|
||||||
|
:: ]
|
||||||
|
:: },
|
||||||
|
:: "/maybe/more": { etc }
|
||||||
|
:: }
|
||||||
|
::
|
||||||
|
++ give-initial-submissions
|
||||||
|
~/ %link-view-initial-submissions
|
||||||
|
|= [p=@ud =requested=path]
|
||||||
|
^- (list card)
|
||||||
|
:_ :: only keep the base case alive (for updates), kick all others
|
||||||
|
::
|
||||||
|
?: &(=(0 p) ?=(~ requested-path)) ~
|
||||||
|
[%give %kick ~ ~]~
|
||||||
|
=; =json
|
||||||
|
[%give %fact ~ %json !>(json)]
|
||||||
|
%+ frond:enjs:format 'initial-submissions'
|
||||||
|
%- pairs:enjs:format
|
||||||
|
%+ turn
|
||||||
|
%~ tap by
|
||||||
|
%+ scry-for (map path submissions)
|
||||||
|
[%submissions requested-path]
|
||||||
|
|= [=path =submissions]
|
||||||
|
^- [@t json]
|
||||||
|
:- (spat path)
|
||||||
|
=; =json
|
||||||
|
:: add unseen count
|
||||||
|
::
|
||||||
|
?> ?=(%o -.json)
|
||||||
|
:- %o
|
||||||
|
%+ ~(put by p.json) 'unseenCount'
|
||||||
|
%- numb:enjs:format
|
||||||
|
%~ wyt in
|
||||||
|
%+ scry-for (set url)
|
||||||
|
[%unseen path]
|
||||||
|
?: &(=(0 p) ?=(~ requested-path))
|
||||||
|
:: for a broad-scope initial result, only give total counts
|
||||||
|
::
|
||||||
|
=, enjs:format
|
||||||
|
%- pairs
|
||||||
|
=+ l=(lent submissions)
|
||||||
|
:~ 'totalItems'^(numb l)
|
||||||
|
'totalPages'^(numb (div l page-size))
|
||||||
|
==
|
||||||
|
%^ page-to-json p
|
||||||
|
%+ get-paginated `p
|
||||||
|
submissions
|
||||||
|
|= =submission
|
||||||
|
^- json
|
||||||
|
=/ =json (submission:en-json submission)
|
||||||
|
?> ?=([%o *] json)
|
||||||
|
:: add in seen status
|
||||||
|
::
|
||||||
|
=. p.json
|
||||||
|
%+ ~(put by p.json) 'seen'
|
||||||
|
:- %b
|
||||||
|
%+ scry-for ?
|
||||||
|
[%seen (build-discussion-path path url.submission)]
|
||||||
|
:: add in comment count
|
||||||
|
::
|
||||||
|
=; comment-count=@ud
|
||||||
|
:- %o
|
||||||
|
%+ ~(put by p.json) 'commentCount'
|
||||||
|
(numb:enjs:format comment-count)
|
||||||
|
%- lent
|
||||||
|
~| [path url.submission]
|
||||||
|
^- comments
|
||||||
|
=- (~(got by (~(got by -) path)) url.submission)
|
||||||
|
%+ scry-for (per-path-url comments)
|
||||||
|
:- %discussions
|
||||||
|
(build-discussion-path path url.submission)
|
||||||
|
::
|
||||||
|
++ give-specific-submission
|
||||||
|
|= [n=@ud =path =url]
|
||||||
|
:_ [%give %kick ~ ~]~
|
||||||
|
=; =json
|
||||||
|
[%give %fact ~ %json !>(json)]
|
||||||
|
%+ frond:enjs:format 'submission'
|
||||||
|
^- json
|
||||||
|
=; sub=(unit submission)
|
||||||
|
?~ sub ~
|
||||||
|
(submission:en-json u.sub)
|
||||||
|
=/ =submissions
|
||||||
|
=- (~(got by -) path)
|
||||||
|
%+ scry-for (map ^path submissions)
|
||||||
|
[%submissions path]
|
||||||
|
|-
|
||||||
|
?~ submissions ~
|
||||||
|
=* sub i.submissions
|
||||||
|
?. =(url.sub url)
|
||||||
|
$(submissions t.submissions)
|
||||||
|
?: =(0 n) `sub
|
||||||
|
$(n (dec n), submissions t.submissions)
|
||||||
|
::
|
||||||
|
++ give-initial-discussions
|
||||||
|
|= [p=@ud =path =url]
|
||||||
|
^- (list card)
|
||||||
|
:_ ?: =(0 p) ~
|
||||||
|
[%give %kick ~ ~]~
|
||||||
|
=; =json
|
||||||
|
[%give %fact ~ %json !>(json)]
|
||||||
|
%+ frond:enjs:format 'initial-discussions'
|
||||||
|
%^ page-to-json p
|
||||||
|
%+ get-paginated `p
|
||||||
|
=- (~(got by (~(got by -) path)) url)
|
||||||
|
%+ scry-for (per-path-url comments)
|
||||||
|
[%discussions (build-discussion-path path url)]
|
||||||
|
comment:en-json
|
||||||
|
::
|
||||||
|
++ send-update
|
||||||
|
|= =update
|
||||||
|
^- card
|
||||||
|
?+ -.update ~|([dap.bowl %unexpected-update -.update] !!)
|
||||||
|
%submissions
|
||||||
|
%+ give-json
|
||||||
|
(update:en-json update)
|
||||||
|
:~ /json/0/submissions
|
||||||
|
(weld /json/0/submissions path.update)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%discussions
|
||||||
|
%+ give-json
|
||||||
|
(update:en-json update)
|
||||||
|
:_ ~
|
||||||
|
%+ weld /json/0/discussions
|
||||||
|
(build-discussion-path [path url]:update)
|
||||||
|
::
|
||||||
|
%observation
|
||||||
|
%+ give-json
|
||||||
|
(update:en-json update)
|
||||||
|
~[/json/seen]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ give-json
|
||||||
|
|= [=json paths=(list path)]
|
||||||
|
^- card
|
||||||
|
[%give %fact paths %json !>(json)]
|
||||||
|
::
|
||||||
|
++ scry-for
|
||||||
|
|* [=mold =path]
|
||||||
|
.^ mold
|
||||||
|
%gx
|
||||||
|
(scot %p our.bowl)
|
||||||
|
%link-store
|
||||||
|
(scot %da now.bowl)
|
||||||
|
(snoc `^path`path %noun)
|
||||||
|
==
|
||||||
|
--
|
1
pkg/arvo/app/link/css/index.css
Normal file
BIN
pkg/arvo/app/link/img/Spinner.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
pkg/arvo/app/link/img/SwitcherClosed.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
pkg/arvo/app/link/img/SwitcherOpen.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
pkg/arvo/app/link/img/Tile.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
pkg/arvo/app/link/img/popout.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
pkg/arvo/app/link/img/search.png
Normal file
After Width: | Height: | Size: 951 B |
20
pkg/arvo/app/link/index.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Links</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
<link rel="stylesheet" href="/~link/css/index.css" />
|
||||||
|
<link rel="icon" type="image/png" href="/~launch/img/Favicon.png">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="w-100 h-100">
|
||||||
|
<div id="root" class="w-100 h-100">
|
||||||
|
</div>
|
||||||
|
<script src="/~channel/channel.js"></script>
|
||||||
|
<script src="/~modulo/session.js"></script>
|
||||||
|
<script src="/~link/js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
1
pkg/arvo/app/link/js/index.js
Normal file
1
pkg/arvo/app/link/js/tile.js
Normal file
248
pkg/arvo/app/metadata-hook.hoon
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
:: metadata-hook: allow syncing foreign metadata
|
||||||
|
::
|
||||||
|
:: watch paths:
|
||||||
|
:: /group/%group-path all updates related to this group
|
||||||
|
::
|
||||||
|
/- *metadata-store, *metadata-hook
|
||||||
|
/+ default-agent, dbug
|
||||||
|
~% %metadata-hook-top ..is ~
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
+$ versioned-state
|
||||||
|
$% state-zero
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ state-zero
|
||||||
|
$: %0
|
||||||
|
synced=(map group-path ship)
|
||||||
|
==
|
||||||
|
--
|
||||||
|
=| state-zero
|
||||||
|
=* state -
|
||||||
|
%- agent:dbug
|
||||||
|
^- agent:gall
|
||||||
|
=<
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* this .
|
||||||
|
hc ~(. +> bowl)
|
||||||
|
def ~(. (default-agent this %|) bowl)
|
||||||
|
::
|
||||||
|
++ on-init
|
||||||
|
[[%pass /updates %agent [our.bowl %metadata-store] %watch /updates]~ this]
|
||||||
|
::
|
||||||
|
++ on-save !>(state)
|
||||||
|
++ on-load |=(=vase `this(state !<(state-zero vase)))
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-peek on-peek:def
|
||||||
|
++ on-arvo on-arvo:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
++ on-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
%metadata-hook-action
|
||||||
|
=^ cards state
|
||||||
|
(poke-hook-action:hc !<(metadata-hook-action vase))
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
%metadata-action
|
||||||
|
[(poke-action:hc !<(metadata-action vase)) this]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ path (on-watch:def path)
|
||||||
|
[%group *] [(watch-group:hc t.path) this]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-agent
|
||||||
|
|= [=wire =sign:agent:gall]
|
||||||
|
^- (quip card _this)
|
||||||
|
?+ -.sign (on-agent:def wire sign)
|
||||||
|
%kick =^(cards state (kick:hc wire) [cards this])
|
||||||
|
%watch-ack =^(cards state (watch-ack:hc wire p.sign) [cards this])
|
||||||
|
%fact
|
||||||
|
?+ p.cage.sign (on-agent:def wire sign)
|
||||||
|
%metadata-update
|
||||||
|
=^ cards state
|
||||||
|
(fact-metadata-update:hc wire !<(metadata-update q.cage.sign))
|
||||||
|
[cards this]
|
||||||
|
==
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
|_ =bowl:gall
|
||||||
|
++ poke-hook-action
|
||||||
|
|= act=metadata-hook-action
|
||||||
|
^- (quip card _state)
|
||||||
|
|^
|
||||||
|
?- -.act
|
||||||
|
%add-owned
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
:- ~
|
||||||
|
?: (~(has by synced) path.act) state
|
||||||
|
state(synced (~(put by synced) path.act our.bowl))
|
||||||
|
::
|
||||||
|
%add-synced
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
=/ =path [%group path.act]
|
||||||
|
?: (~(has by synced) path.act) [~ state]
|
||||||
|
:_ state(synced (~(put by synced) path.act ship.act))
|
||||||
|
[%pass path %agent [ship.act %metadata-hook] %watch path]~
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
=/ ship (~(get by synced) path.act)
|
||||||
|
?~ ship [~ state]
|
||||||
|
?: &(!=(u.ship src.bowl) ?!((team:title our.bowl src.bowl)))
|
||||||
|
[~ state]
|
||||||
|
:_ state(synced (~(del by synced) path.act))
|
||||||
|
%- zing
|
||||||
|
:~ (unsubscribe [%group path.act] u.ship)
|
||||||
|
[%give %kick ~[[%group path.act]] ~]~
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ unsubscribe
|
||||||
|
|= [=path =ship]
|
||||||
|
^- (list card)
|
||||||
|
?: =(ship our.bowl)
|
||||||
|
[%pass path %agent [our.bowl %metadata-store] %leave ~]~
|
||||||
|
[%pass path %agent [ship %metadata-hook] %leave ~]~
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ poke-action
|
||||||
|
|= act=metadata-action
|
||||||
|
^- (list card)
|
||||||
|
|^
|
||||||
|
?: (team:title our.bowl src.bowl)
|
||||||
|
?- -.act
|
||||||
|
%add (send group-path.act)
|
||||||
|
%remove (send group-path.act)
|
||||||
|
==
|
||||||
|
?> (is-permitted src.bowl group-path.act)
|
||||||
|
?- -.act
|
||||||
|
%add (metadata-poke our.bowl %metadata-store)
|
||||||
|
%remove (metadata-poke our.bowl %metadata-store)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ send
|
||||||
|
|= =group-path
|
||||||
|
^- (list card)
|
||||||
|
=/ =ship
|
||||||
|
%+ slav %p
|
||||||
|
?: (is-managed group-path) (snag 0 group-path)
|
||||||
|
(snag 1 group-path)
|
||||||
|
=/ app ?:(=(ship our.bowl) %metadata-store %metadata-hook)
|
||||||
|
(metadata-poke ship app)
|
||||||
|
::
|
||||||
|
++ metadata-poke
|
||||||
|
|= [=ship app=@tas]
|
||||||
|
^- (list card)
|
||||||
|
[%pass / %agent [ship app] %poke %metadata-action !>(act)]~
|
||||||
|
::
|
||||||
|
++ is-managed
|
||||||
|
|= =path
|
||||||
|
^- ?
|
||||||
|
?> ?=(^ path)
|
||||||
|
!=(i.path '~')
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ watch-group
|
||||||
|
|= =path
|
||||||
|
^- (list card)
|
||||||
|
|^
|
||||||
|
?> =(our.bowl (~(got by synced) path))
|
||||||
|
?> (is-permitted src.bowl path)
|
||||||
|
%+ turn ~(tap by (metadata-scry path))
|
||||||
|
|= [[=group-path =resource] =metadata]
|
||||||
|
^- card
|
||||||
|
[%give %fact ~ %metadata-update !>([%add group-path resource metadata])]
|
||||||
|
::
|
||||||
|
++ metadata-scry
|
||||||
|
|= pax=^path
|
||||||
|
^- associations
|
||||||
|
=. pax ;:(weld /=metadata-store/(scot %da now.bowl)/group pax /noun)
|
||||||
|
.^(associations %gx pax)
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ fact-metadata-update
|
||||||
|
|= [wir=wire fact=metadata-update]
|
||||||
|
^- (quip card _state)
|
||||||
|
|^
|
||||||
|
[?:((team:title our.bowl src.bowl) handle-local handle-foreign) state]
|
||||||
|
::
|
||||||
|
++ handle-local
|
||||||
|
?+ -.fact ~
|
||||||
|
%add
|
||||||
|
?. (~(has by synced) group-path.fact) ~
|
||||||
|
(give group-path.fact fact)
|
||||||
|
::
|
||||||
|
%update-metadata
|
||||||
|
?. (~(has by synced) group-path.fact) ~
|
||||||
|
(give group-path.fact fact)
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
?. (~(has by synced) group-path.fact) ~
|
||||||
|
(give group-path.fact fact)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-foreign
|
||||||
|
?+ -.fact ~
|
||||||
|
%add
|
||||||
|
?. =(src.bowl (~(got by synced) group-path.fact)) ~
|
||||||
|
(poke fact)
|
||||||
|
::
|
||||||
|
%update-metadata
|
||||||
|
?. =(src.bowl (~(got by synced) group-path.fact)) ~
|
||||||
|
(poke [%add +.fact])
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
?. =(src.bowl (~(got by synced) group-path.fact)) ~
|
||||||
|
(poke fact)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ give
|
||||||
|
|= [=path upd=metadata-update]
|
||||||
|
^- (list card)
|
||||||
|
[%give %fact ~[[%group path]] %metadata-update !>(upd)]~
|
||||||
|
::
|
||||||
|
++ poke
|
||||||
|
|= act=metadata-action
|
||||||
|
^- (list card)
|
||||||
|
[%pass / %agent [our.bowl %metadata-store] %poke %metadata-action !>(act)]~
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ kick
|
||||||
|
|= wir=wire
|
||||||
|
^- (quip card _state)
|
||||||
|
:_ state
|
||||||
|
?+ wir !!
|
||||||
|
[%updates ~]
|
||||||
|
[%pass /updates %agent [our.bowl %metadata-store] %watch /updates]~
|
||||||
|
::
|
||||||
|
[%group @ *]
|
||||||
|
?. (~(has by synced) t.wir) ~
|
||||||
|
=/ =ship (~(got by synced) t.wir)
|
||||||
|
?: =(ship our.bowl)
|
||||||
|
[%pass wir %agent [our.bowl %metadata-store] %watch wir]~
|
||||||
|
[%pass wir %agent [ship %metadata-hook] %watch wir]~
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ watch-ack
|
||||||
|
|= [wir=wire saw=(unit tang)]
|
||||||
|
^- (quip card _state)
|
||||||
|
?> ?=(^ wir)
|
||||||
|
[~ ?~(saw state state(synced (~(del by synced) t.wir)))]
|
||||||
|
::
|
||||||
|
++ is-permitted
|
||||||
|
|= [=ship pax=path]
|
||||||
|
^- ?
|
||||||
|
=. pax
|
||||||
|
;: weld
|
||||||
|
/=permission-store/(scot %da now.bowl)/permitted
|
||||||
|
[(scot %p ship) pax]
|
||||||
|
/noun
|
||||||
|
==
|
||||||
|
.^(? %gx pax)
|
||||||
|
--
|
205
pkg/arvo/app/metadata-store.hoon
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
:: metadata-store: data store for application metadata and mappings
|
||||||
|
:: between groups and resources within applications
|
||||||
|
::
|
||||||
|
:: group-paths are expected to be an existing group path
|
||||||
|
:: resources are expected to correspond to existing app paths
|
||||||
|
::
|
||||||
|
:: note: when scrying for metadata, to make the arguments safe in paths,
|
||||||
|
:: encode group-path and app-path using (scot %t (spat group-path))
|
||||||
|
::
|
||||||
|
:: +watch paths:
|
||||||
|
:: /all assocations + updates
|
||||||
|
:: /updates just updates
|
||||||
|
:: /app-name/%app-name specific app's associations + updates
|
||||||
|
::
|
||||||
|
:: +peek paths:
|
||||||
|
:: /associations all associations
|
||||||
|
:: /group-indices all group indices
|
||||||
|
:: /app-indices all app indices
|
||||||
|
:: /resource-indices all resource indices
|
||||||
|
:: /metadata/%group-path/%app-name/%app-path specific metadatum
|
||||||
|
:: /app-name/%app-name associations for app
|
||||||
|
:: /group/%group-path associations for group
|
||||||
|
::
|
||||||
|
/+ *metadata-json, default-agent, verb, dbug
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
::
|
||||||
|
+$ versioned-state
|
||||||
|
$% state-zero
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ state-zero
|
||||||
|
$: %0
|
||||||
|
=associations
|
||||||
|
group-indices=(jug group-path resource)
|
||||||
|
app-indices=(jug app-name [group-path app-path])
|
||||||
|
resource-indices=(jug resource group-path)
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
=| state-zero
|
||||||
|
=* state -
|
||||||
|
%+ verb |
|
||||||
|
%- agent:dbug
|
||||||
|
^- agent:gall
|
||||||
|
=<
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* this .
|
||||||
|
metadata-core +>
|
||||||
|
mc ~(. metadata-core bowl)
|
||||||
|
def ~(. (default-agent this %|) bowl)
|
||||||
|
::
|
||||||
|
++ on-init on-init:def
|
||||||
|
++ on-save !>(state)
|
||||||
|
++ on-load
|
||||||
|
|= old=vase
|
||||||
|
`this(state !<(state-zero old))
|
||||||
|
::
|
||||||
|
++ on-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
^- (quip card _this)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
=^ cards state
|
||||||
|
?: ?=(%metadata-action mark)
|
||||||
|
(poke-metadata-action:mc !<(metadata-action vase))
|
||||||
|
(on-poke:def mark vase)
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
|^
|
||||||
|
=/ cards=(list card)
|
||||||
|
?+ path (on-watch:def path)
|
||||||
|
[%all ~] (give %metadata-update !>([%associations associations]))
|
||||||
|
[%updates ~] ~
|
||||||
|
[%app-name @ ~]
|
||||||
|
=/ =app-name i.t.path
|
||||||
|
=/ app-indices (metadata-for-app:mc app-name)
|
||||||
|
(give %metadata-update !>([%associations app-indices]))
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ give
|
||||||
|
|= =cage
|
||||||
|
^- (list card)
|
||||||
|
[%give %fact ~ cage]~
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
::
|
||||||
|
++ on-peek
|
||||||
|
|= =path
|
||||||
|
^- (unit (unit cage))
|
||||||
|
?+ path (on-peek:def path)
|
||||||
|
[%y %group-indices ~] ``noun+!>(group-indices)
|
||||||
|
[%y %app-indices ~] ``noun+!>(app-indices)
|
||||||
|
[%y %resource-indices ~] ``noun+!>(resource-indices)
|
||||||
|
[%x %associations ~] ``noun+!>(associations)
|
||||||
|
[%x %app-name @ ~]
|
||||||
|
=/ =app-name i.t.t.path
|
||||||
|
``noun+!>((metadata-for-app:mc app-name))
|
||||||
|
::
|
||||||
|
[%x %group *]
|
||||||
|
=/ =group-path t.t.path
|
||||||
|
``noun+!>((metadata-for-group:mc group-path))
|
||||||
|
::
|
||||||
|
[%x %metadata @ @ @ ~]
|
||||||
|
=/ =group-path (stab (slav %t i.t.t.path))
|
||||||
|
=/ =resource [`@tas`i.t.t.t.path (stab (slav %t i.t.t.t.t.path))]
|
||||||
|
``noun+!>((~(get by associations) [group-path resource]))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-agent on-agent:def
|
||||||
|
++ on-arvo on-arvo:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
||||||
|
::
|
||||||
|
|_ =bowl:gall
|
||||||
|
++ poke-metadata-action
|
||||||
|
|= act=metadata-action
|
||||||
|
^- (quip card _state)
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
?- -.act
|
||||||
|
%add
|
||||||
|
(handle-add group-path.act resource.act metadata.act)
|
||||||
|
::
|
||||||
|
%remove
|
||||||
|
(handle-remove group-path.act resource.act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-add
|
||||||
|
|= [=group-path =resource =metadata]
|
||||||
|
^- (quip card _state)
|
||||||
|
:- %+ send-diff app-name.resource
|
||||||
|
?. (~(has by resource-indices) resource)
|
||||||
|
[%add group-path resource metadata]
|
||||||
|
[%update-metadata group-path resource metadata]
|
||||||
|
%= state
|
||||||
|
associations
|
||||||
|
(~(put by associations) [group-path resource] metadata)
|
||||||
|
::
|
||||||
|
group-indices
|
||||||
|
(~(put ju group-indices) group-path resource)
|
||||||
|
::
|
||||||
|
app-indices
|
||||||
|
(~(put ju app-indices) app-name.resource [group-path app-path.resource])
|
||||||
|
::
|
||||||
|
resource-indices
|
||||||
|
(~(put ju resource-indices) resource group-path)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ handle-remove
|
||||||
|
|= [=group-path =resource]
|
||||||
|
^- (quip card _state)
|
||||||
|
:- (send-diff app-name.resource [%remove group-path resource])
|
||||||
|
%= state
|
||||||
|
associations
|
||||||
|
(~(del by associations) [group-path resource])
|
||||||
|
::
|
||||||
|
group-indices
|
||||||
|
(~(del ju group-indices) group-path resource)
|
||||||
|
::
|
||||||
|
app-indices
|
||||||
|
(~(del ju app-indices) app-name.resource [group-path app-path.resource])
|
||||||
|
::
|
||||||
|
resource-indices
|
||||||
|
(~(del ju resource-indices) resource group-path)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ metadata-for-app
|
||||||
|
|= =app-name
|
||||||
|
^- ^associations
|
||||||
|
%- ~(gas by *^associations)
|
||||||
|
%+ turn ~(tap in (~(gut by app-indices) app-name ~))
|
||||||
|
|= [=group-path =app-path]
|
||||||
|
:- [group-path [app-name app-path]]
|
||||||
|
(~(got by associations) [group-path [app-name app-path]])
|
||||||
|
::
|
||||||
|
++ metadata-for-group
|
||||||
|
|= =group-path
|
||||||
|
^- ^associations
|
||||||
|
%- ~(gas by *^associations)
|
||||||
|
%+ turn ~(tap in (~(gut by group-indices) group-path ~))
|
||||||
|
|= =resource
|
||||||
|
:- [group-path resource]
|
||||||
|
(~(got by associations) [group-path resource])
|
||||||
|
::
|
||||||
|
++ send-diff
|
||||||
|
|= [=app-name upd=metadata-update]
|
||||||
|
^- (list card)
|
||||||
|
|^
|
||||||
|
%- zing
|
||||||
|
:~ (update-subscribers /all upd)
|
||||||
|
(update-subscribers /updates upd)
|
||||||
|
(update-subscribers [%app-name app-name ~] upd)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ update-subscribers
|
||||||
|
|= [pax=path upd=metadata-update]
|
||||||
|
^- (list card)
|
||||||
|
[%give %fact ~[pax] %metadata-update !>(upd)]~
|
||||||
|
--
|
||||||
|
--
|
@ -3,7 +3,7 @@
|
|||||||
:: mirror the ships in specified groups to specified permission paths
|
:: mirror the ships in specified groups to specified permission paths
|
||||||
::
|
::
|
||||||
/- *group-store, *permission-group-hook
|
/- *group-store, *permission-group-hook
|
||||||
/+ *permission-json, default-agent, verb
|
/+ *permission-json, default-agent, verb, dbug
|
||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ state
|
+$ state
|
||||||
@ -25,6 +25,7 @@
|
|||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
%+ verb |
|
%+ verb |
|
||||||
|
%- agent:dbug
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
/- *permission-hook
|
/- *permission-hook
|
||||||
/+ *permission-json, default-agent, verb, dbug
|
/+ *permission-json, default-agent, verb, dbug
|
||||||
::
|
::
|
||||||
|
~% %permission-hook-top ..is ~
|
||||||
|%
|
|%
|
||||||
+$ state
|
+$ state
|
||||||
$% [%0 state-0]
|
$% [%0 state-0]
|
||||||
@ -195,7 +196,15 @@
|
|||||||
%delete
|
%delete
|
||||||
?. (~(has by synced) path.diff)
|
?. (~(has by synced) path.diff)
|
||||||
[~ state]
|
[~ state]
|
||||||
:_ state(synced (~(del by synced) path.diff))
|
=/ control=(unit path)
|
||||||
|
=+ (~(got by synced) path.diff)
|
||||||
|
?. =(our.bowl ship) ~
|
||||||
|
`access-control
|
||||||
|
:_ %_ state
|
||||||
|
synced (~(del by synced) path.diff)
|
||||||
|
access-control ?~ control access-control
|
||||||
|
(~(del ju access-control) u.control path.diff)
|
||||||
|
==
|
||||||
:_ ~
|
:_ ~
|
||||||
:* %pass
|
:* %pass
|
||||||
[%permission path.diff]
|
[%permission path.diff]
|
||||||
|
BIN
pkg/arvo/app/publish/img/Spinner.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
pkg/arvo/app/publish/img/SwitcherClosed.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
pkg/arvo/app/publish/img/SwitcherOpen.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 245 B |
BIN
pkg/arvo/app/publish/img/popout.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
pkg/arvo/app/publish/img/search.png
Normal file
After Width: | Height: | Size: 951 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 3.7 KiB |
@ -10,13 +10,13 @@
|
|||||||
=content "width=device-width, initial-scale=1, shrink-to-fit=no";
|
=content "width=device-width, initial-scale=1, shrink-to-fit=no";
|
||||||
;link(rel "stylesheet", href "/~publish/index.css");
|
;link(rel "stylesheet", href "/~publish/index.css");
|
||||||
;link(rel "icon", type "image/png", href "/~launch/img/Favicon.png");
|
;link(rel "icon", type "image/png", href "/~launch/img/Favicon.png");
|
||||||
;script@"/~/channel/channel.js";
|
;script@"/~channel/channel.js";
|
||||||
;script@"/~modulo/session.js";
|
;script@"/~modulo/session.js";
|
||||||
;script: window.injectedState = {(en-json:html inject)}
|
;script: window.injectedState = {(en-json:html inject)}
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
;body
|
;body
|
||||||
;div#root;
|
;div#root.w-100.h-100;
|
||||||
;script@"/~publish/index.js";
|
;script@"/~publish/index.js";
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
|
96
pkg/arvo/app/s3-store.hoon
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/- *s3
|
||||||
|
/+ s3-json, default-agent, verb, dbug
|
||||||
|
~% %s3-top ..is ~
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
+$ versioned-state
|
||||||
|
$% state-zero
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ state-zero [%0 =credentials =configuration]
|
||||||
|
--
|
||||||
|
::
|
||||||
|
=| state-zero
|
||||||
|
=* state -
|
||||||
|
::
|
||||||
|
%- agent:dbug
|
||||||
|
%+ verb |
|
||||||
|
^- agent:gall
|
||||||
|
~% %s3-agent-core ..card ~
|
||||||
|
|_ =bowl:gall
|
||||||
|
+* this .
|
||||||
|
def ~(. (default-agent this %|) bowl)
|
||||||
|
::
|
||||||
|
++ on-init on-init:def
|
||||||
|
++ on-save !>(state)
|
||||||
|
++ on-load
|
||||||
|
|= old-vase=vase
|
||||||
|
[~ this(state !<(state-zero old-vase))]
|
||||||
|
::
|
||||||
|
++ on-poke
|
||||||
|
~/ %s3-poke
|
||||||
|
|= [=mark =vase]
|
||||||
|
^- (quip card _this)
|
||||||
|
|^
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
=^ cards state
|
||||||
|
?+ mark (on-poke:def mark vase)
|
||||||
|
%s3-action (poke-action !<(action vase))
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ poke-action
|
||||||
|
|= act=action
|
||||||
|
^- (quip card _state)
|
||||||
|
:- [%give %fact [/all]~ %s3-update !>(act)]~
|
||||||
|
?- -.act
|
||||||
|
%set-endpoint
|
||||||
|
state(endpoint.credentials endpoint.act)
|
||||||
|
::
|
||||||
|
%set-access-key-id
|
||||||
|
state(access-key-id.credentials access-key-id.act)
|
||||||
|
::
|
||||||
|
%set-secret-access-key
|
||||||
|
state(secret-access-key.credentials secret-access-key.act)
|
||||||
|
::
|
||||||
|
%set-current-bucket
|
||||||
|
%_ state
|
||||||
|
current-bucket.configuration bucket.act
|
||||||
|
buckets.configuration (~(put in buckets.configuration) bucket.act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%add-bucket
|
||||||
|
state(buckets.configuration (~(put in buckets.configuration) bucket.act))
|
||||||
|
::
|
||||||
|
%remove-bucket
|
||||||
|
state(buckets.configuration (~(del in buckets.configuration) bucket.act))
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
~/ %s3-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
|^
|
||||||
|
?> (team:title our.bowl src.bowl)
|
||||||
|
=/ cards=(list card)
|
||||||
|
?+ path (on-watch:def path)
|
||||||
|
[%all ~]
|
||||||
|
:~ (give %s3-update !>([%credentials credentials]))
|
||||||
|
(give %s3-update !>([%configuration configuration]))
|
||||||
|
==
|
||||||
|
==
|
||||||
|
[cards this]
|
||||||
|
::
|
||||||
|
++ give
|
||||||
|
|= =cage
|
||||||
|
^- card
|
||||||
|
[%give %fact ~ cage]
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-peek on-peek:def
|
||||||
|
++ on-agent on-agent:def
|
||||||
|
++ on-arvo on-arvo:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
@ -54,7 +54,7 @@
|
|||||||
:_ this
|
:_ this
|
||||||
:~ [%pass /bind/soto %arvo %e %connect [~ /'~dojo'] %soto]
|
:~ [%pass /bind/soto %arvo %e %connect [~ /'~dojo'] %soto]
|
||||||
:* %pass /launch/soto %agent [our.bol %launch] %poke
|
:* %pass /launch/soto %agent [our.bol %launch] %poke
|
||||||
%launch-action !>([%soto /sototile '/~dojo/js/tile.js'])
|
%launch-action !>([%add %soto /sototile '/~dojo/js/tile.js'])
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
|
BIN
pkg/arvo/app/soto/img/Spinner.png
Normal file
After Width: | Height: | Size: 679 B |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
pkg/arvo/app/soto/img/popout.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
@ -6,9 +6,11 @@
|
|||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||||
<link rel="stylesheet" href="/~dojo/css/index.css" />
|
<link rel="stylesheet" href="/~dojo/css/index.css" />
|
||||||
|
<link rel="icon" type="image/png" href="/~launch/img/Favicon.png">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-black">
|
<body class="w-100 h-100">
|
||||||
<div id="root" />
|
<div id="root" class="w-100 h-100">
|
||||||
|
</div>
|
||||||
<script src="/~/channel/channel.js"></script>
|
<script src="/~/channel/channel.js"></script>
|
||||||
<script src="/~modulo/session.js"></script>
|
<script src="/~modulo/session.js"></script>
|
||||||
<script src="/~dojo/js/index.js"></script>
|
<script src="/~dojo/js/index.js"></script>
|
||||||
|