mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-24 02:24:18 +03:00
master without pills, hopefully
This commit is contained in:
parent
aa8baa367c
commit
625f855f24
24
.mailmap
Normal file
24
.mailmap
Normal file
@ -0,0 +1,24 @@
|
||||
b <benjamin@tlon.io>
|
||||
b <benjamin@tlon.io> <42358674+benjamin-tlon@users.noreply.github.com>
|
||||
BernardoDeLaPlaz <BernardoDeLaPlaz@users.noreply.github.com> <40804016+BernardoDeLaPlaz@users.noreply.github.com>
|
||||
BernardoDeLaPlaz <BernardoDeLaPlaz@users.noreply.github.com> <tjic_BernardoDeLaPlaz_github@tjic.com>
|
||||
Elliot Glaysher <elliot@tlon.io> <glaysher@umich.edu>
|
||||
Fang <git@fang.io> <Fang-@users.noreply.github.com>
|
||||
Fang <git@fang.io> <fang@fang.io>
|
||||
Frank Ch. Eigler <fche@redhat.com> <fche@elastic.org>
|
||||
Isaac Visintainer <isaac.visintainer@gmail.com>
|
||||
Isaac Visintainer <isaac.visintainer@gmail.com> <isaacv@tlon.io>
|
||||
Jared Tobin <jared@jtobin.io> <jared@tlon.io>
|
||||
John Franklin <jfranklin9000@gmail.com>
|
||||
Joe Bryan <joemfb@gmail.com>
|
||||
Jose L. Bellod Cisneros <bellod.cisneros@gmail.com>
|
||||
Jōshin <git@wholezero.org>
|
||||
Jōshin <git@wholezero.org> <_@wholezero.org>
|
||||
Joshua Reagan <joshuareagan@gmail.com>
|
||||
Joshua Reagan <joshuareagan@gmail.com> <joshuareagan@users.noreply.github.com>
|
||||
Logan Allen <loganallc@gmail.com>
|
||||
Logan Allen <loganallc@gmail.com> <logan@tlon.io>
|
||||
Matilde Park <matilde@park.computer> <matilde@tlon.io>
|
||||
pilfer-pandex <pilfer-pandex@users.noreply.github.com> <47340789+pilfer-pandex@users.noreply.github.com>
|
||||
Robert <robert@tlon.io>
|
||||
Ted Blackman <ted@tlon.io> <ted@3scan.com>
|
@ -40,7 +40,7 @@ $ urbit my-fake-zod
|
||||
|
||||
### Contributing
|
||||
|
||||
The canonical source tree is located in the `master` branch at
|
||||
The canonical source tree is the `master` branch of
|
||||
[https://github.com/urbit/urbit][repo]. You should typically branch off of
|
||||
`master` when commencing new work; similarly, when we pull in your
|
||||
contribution, we'll do so by merging it to `master`.
|
||||
@ -51,6 +51,19 @@ email them to maintainers, or request a maintainer pull from your tree directly
|
||||
-- but note that some maintainers will be more receptive to these methods than
|
||||
others.
|
||||
|
||||
When contributing changes, via whatever means, make sure you describe them
|
||||
appropriately. You should attach a reasonably high-level summary of what the
|
||||
changes are and what they do; reference any useful background material that may
|
||||
exist, e.g. a GitHub issue, a mailing list discussion, a UP, etc. [Here][jbpr]
|
||||
is a good example of a pull request with a useful, concise description.
|
||||
|
||||
If your changes replace significant extant functionality, be sure to compare
|
||||
them with the thing you're replacing. You may also want to cc maintainers,
|
||||
reviewers, or other parties who might have a particular interest in what you're
|
||||
contributing.
|
||||
|
||||
[jbpr]: https://github.com/urbit/urbit/pull/1782
|
||||
|
||||
### Hygiene
|
||||
|
||||
Commits should generally be relevant, atomic, and have descriptions formatted
|
||||
|
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bb0a7faca368603e55469035da0deae500a0ad69c9858699a49118f8310b16b2
|
||||
size 12603952
|
@ -1,19 +1,11 @@
|
||||
{ pkgs, tlon, deps, pier, arvo, debug }:
|
||||
|
||||
let
|
||||
|
||||
urbitExe = if debug
|
||||
then "${tlon.urbit-debug}/bin/urbit-debug -g"
|
||||
else "${tlon.urbit}/bin/urbit";
|
||||
|
||||
in
|
||||
{ pkgs, herb, urbit, pier, arvo }:
|
||||
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
name = "brass";
|
||||
builder = ./builder.sh;
|
||||
buildInputs = [ tlon.herb pkgs.coreutils ];
|
||||
buildInputs = [ herb pkgs.coreutils ];
|
||||
|
||||
URBIT = urbitExe;
|
||||
URBIT = ubit.meta.exe;
|
||||
PIER = pier;
|
||||
ARVO = arvo;
|
||||
}
|
||||
|
@ -2,29 +2,29 @@
|
||||
|
||||
let
|
||||
|
||||
deps = import ../deps { inherit pkgs; };
|
||||
tlon = import ../pkgs { inherit pkgs; };
|
||||
arvo = tlon.arvo;
|
||||
urbit = tlon.urbit;
|
||||
herb = tlon.herb;
|
||||
urbit = if debug then tlon.urbit-debug else tlon.urbit;
|
||||
|
||||
bootbrass = ../../bin/brass.pill;
|
||||
bootsolid = ../../bin/solid.pill;
|
||||
|
||||
rawzod = import ./fakeship {
|
||||
inherit pkgs tlon deps debug;
|
||||
inherit pkgs herb urbit;
|
||||
pill = bootsolid;
|
||||
ship = "zod";
|
||||
arvo = null;
|
||||
};
|
||||
|
||||
zod = import ./fakeship {
|
||||
inherit pkgs tlon deps arvo debug;
|
||||
inherit pkgs herb urbit arvo;
|
||||
pill = bootsolid;
|
||||
ship = "zod";
|
||||
};
|
||||
|
||||
bus = import ./fakeship {
|
||||
inherit pkgs tlon deps arvo debug;
|
||||
inherit pkgs herb urbit arvo;
|
||||
pill = bootsolid;
|
||||
ship = "bus";
|
||||
};
|
||||
@ -34,23 +34,28 @@ in
|
||||
rec {
|
||||
|
||||
test = import ./test {
|
||||
inherit pkgs tlon deps debug;
|
||||
inherit pkgs herb urbit;
|
||||
ship = bus;
|
||||
};
|
||||
|
||||
solid = import ./solid {
|
||||
inherit arvo pkgs tlon deps debug;
|
||||
inherit pkgs herb urbit arvo;
|
||||
pier = rawzod;
|
||||
};
|
||||
|
||||
brass = import ./brass {
|
||||
inherit arvo pkgs tlon deps debug;
|
||||
inherit pkgs herb urbit arvo;
|
||||
pier = zod;
|
||||
};
|
||||
|
||||
ivory = import ./ivory {
|
||||
inherit arvo pkgs tlon deps debug;
|
||||
inherit pkgs herb urbit arvo;
|
||||
pier = zod;
|
||||
};
|
||||
|
||||
image = import ./image {
|
||||
inherit pkgs urbit;
|
||||
pill = bootsolid;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,10 @@
|
||||
{ pkgs, tlon, deps, pill, ship, arvo, debug }:
|
||||
|
||||
let
|
||||
|
||||
urbitExe = if debug
|
||||
then "${tlon.urbit-debug}/bin/urbit-debug -g"
|
||||
else "${tlon.urbit}/bin/urbit";
|
||||
|
||||
in
|
||||
{ pkgs, herb, urbit, pill, ship, arvo }:
|
||||
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "fake" + ship;
|
||||
builder = ./builder.sh;
|
||||
buildInputs = [ tlon.herb ];
|
||||
URBIT = urbitExe;
|
||||
buildInputs = [ herb ];
|
||||
URBIT = urbit.meta.exe;
|
||||
ARVO = arvo;
|
||||
PILL = pill;
|
||||
SHIP = ship;
|
||||
|
60
nix/ops/image/default.nix
Normal file
60
nix/ops/image/default.nix
Normal file
@ -0,0 +1,60 @@
|
||||
{ pkgs, urbit, pill }:
|
||||
|
||||
let
|
||||
|
||||
name = urbit.meta.name;
|
||||
debug = urbit.meta.debug;
|
||||
exe = ''${urbit.meta.exe} "$@"'';
|
||||
|
||||
coredump = ''
|
||||
ulimit -c unlimited
|
||||
|
||||
${exe} || \
|
||||
${pkgs.gdb}/bin/gdb -ex "thread apply all bt" -ex "set pagination 0" -batch \
|
||||
${urbit.meta.bin} \
|
||||
/tmp/cores/core*
|
||||
'';
|
||||
|
||||
entrypoint = pkgs.writeScript "entrypoint.sh" ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
${pkgs.coreutils}/bin/ln -sf ${pill} /data/urbit.pill
|
||||
|
||||
${if debug then coredump else exe}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
pkgs.dockerTools.buildImage {
|
||||
inherit name;
|
||||
|
||||
runAsRoot = ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin:$PATH
|
||||
|
||||
${pkgs.dockerTools.shadowSetup}
|
||||
|
||||
mkdir -p /data /tmp/cores
|
||||
'';
|
||||
|
||||
config = {
|
||||
Entrypoint = entrypoint;
|
||||
|
||||
WorkingDir = "/data";
|
||||
|
||||
Volumes = {
|
||||
"/data" = {};
|
||||
"/tmp" = {};
|
||||
};
|
||||
|
||||
ExposedPorts = {
|
||||
"80/tcp" = {};
|
||||
"443/tcp" = {};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,19 +1,11 @@
|
||||
{ pkgs, tlon, deps, pier, arvo, debug }:
|
||||
|
||||
let
|
||||
|
||||
urbitExe = if debug
|
||||
then "${tlon.urbit-debug}/bin/urbit-debug -g"
|
||||
else "${tlon.urbit}/bin/urbit";
|
||||
|
||||
in
|
||||
{ pkgs, herb, urbit, pier, arvo }:
|
||||
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
name = "ivory";
|
||||
builder = ./builder.sh;
|
||||
buildInputs = [ tlon.herb pkgs.coreutils ];
|
||||
buildInputs = [ herb pkgs.coreutils ];
|
||||
|
||||
URBIT = urbitExe;
|
||||
URBIT = urbit.meta.exe;
|
||||
PIER = pier;
|
||||
ARVO = arvo;
|
||||
}
|
||||
|
@ -1,19 +1,11 @@
|
||||
{ pkgs, tlon, deps, pier, arvo, debug }:
|
||||
|
||||
let
|
||||
|
||||
urbitExe = if debug
|
||||
then "${tlon.urbit-debug}/bin/urbit-debug -g"
|
||||
else "${tlon.urbit}/bin/urbit";
|
||||
|
||||
in
|
||||
{ pkgs, herb, urbit, pier, arvo }:
|
||||
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
name = "solid";
|
||||
builder = ./builder.sh;
|
||||
buildInputs = [ tlon.herb ];
|
||||
buildInputs = [ herb ];
|
||||
|
||||
URBIT = urbitExe;
|
||||
URBIT = urbit.exe;
|
||||
PIER = pier;
|
||||
ARVO = arvo;
|
||||
}
|
||||
|
@ -1,18 +1,10 @@
|
||||
{ pkgs, tlon, deps, ship, debug }:
|
||||
|
||||
let
|
||||
|
||||
urbitExe = if debug
|
||||
then "${tlon.urbit-debug}/bin/urbit-debug -g"
|
||||
else "${tlon.urbit}/bin/urbit";
|
||||
|
||||
in
|
||||
{ pkgs, herb, urbit, ship }:
|
||||
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
name = "test";
|
||||
builder = ./builder.sh;
|
||||
buildInputs = [ tlon.herb ];
|
||||
buildInputs = [ herb ];
|
||||
|
||||
URBIT = urbitExe;
|
||||
URBIT = urbit.meta.exe;
|
||||
SHIP = ship;
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ let
|
||||
inherit (deps) secp256k1 h2o ivory-header ca-header;
|
||||
};
|
||||
|
||||
urbit = mkUrbit { debug=false; };
|
||||
urbit-debug = mkUrbit { debug=true; };
|
||||
urbit = mkUrbit { debug = false; };
|
||||
urbit-debug = mkUrbit { debug = true; };
|
||||
|
||||
in
|
||||
|
||||
|
@ -9,6 +9,13 @@ let
|
||||
name =
|
||||
if debug then "urbit-debug" else "urbit";
|
||||
|
||||
meta = rec {
|
||||
inherit debug;
|
||||
bin = "${urbit}/bin/${name}";
|
||||
flags = if debug then "-g" else "";
|
||||
exe = "${meta.bin} ${meta.flags}";
|
||||
};
|
||||
|
||||
deps =
|
||||
with pkgs;
|
||||
[ curl gmp libsigsegv ncurses openssl zlib lmdb ];
|
||||
@ -16,21 +23,22 @@ let
|
||||
vendor =
|
||||
[ argon2 softfloat3 ed25519 ent ge-additions h2o scrypt uv murmur3 secp256k1 sni ivory-header ca-header ];
|
||||
|
||||
urbit = pkgs.stdenv.mkDerivation {
|
||||
inherit name meta;
|
||||
exename = name;
|
||||
src = ../../../pkg/urbit;
|
||||
builder = ./builder.sh;
|
||||
nativeBuildInputs = deps ++ vendor;
|
||||
|
||||
# See https://github.com/NixOS/nixpkgs/issues/18995
|
||||
hardeningDisable = if debug then [ "all" ] else [];
|
||||
|
||||
CFLAGS = if debug then "-O3 -g -Werror" else "-O3 -Werror";
|
||||
MEMORY_DEBUG = debug;
|
||||
CPU_DEBUG = debug;
|
||||
EVENT_TIME_DEBUG = false;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = name;
|
||||
exename = name;
|
||||
src = ../../../pkg/urbit;
|
||||
builder = ./builder.sh;
|
||||
|
||||
nativeBuildInputs = deps ++ vendor;
|
||||
|
||||
# See https://github.com/NixOS/nixpkgs/issues/18995
|
||||
hardeningDisable = if debug then [ "all" ] else [];
|
||||
|
||||
CFLAGS = if debug then "-O3 -g -Werror" else "-O3 -Werror";
|
||||
MEMORY_DEBUG = debug;
|
||||
CPU_DEBUG = debug;
|
||||
EVENT_TIME_DEBUG = false;
|
||||
}
|
||||
urbit
|
||||
|
@ -4,7 +4,10 @@ A clean-slate operating system.
|
||||
|
||||
## Usage
|
||||
|
||||
To run Arvo, you'll need [Urbit](https://github.com/urbit/urbit/). To install Urbit and run Arvo please follow the instructions in the [getting started docs](https://urbit.org/docs/getting-started/). You'll be on the live network in a few minutes.
|
||||
To run Arvo, you'll need [Urbit](https://github.com/urbit/urbit/). To install
|
||||
Urbit and run Arvo please follow the instructions in the [getting started
|
||||
docs](https://urbit.org/docs/getting-started/). You'll be on the live network
|
||||
in a few minutes.
|
||||
|
||||
If you're doing development on Arvo, keep reading.
|
||||
|
||||
@ -56,11 +59,16 @@ Most parts of Arvo have dedicated maintainers.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions of any form are more than welcome! If something doesn't seem right, and there is no issue about it yet, feel free to open one.
|
||||
Contributions of any form are more than welcome! Please take a look at our
|
||||
[contributing guidelines][cont] for details on our git practices, coding
|
||||
styles, how we manage issues, and so on.
|
||||
|
||||
If you're looking to make code contributions, there are a few things you can do:
|
||||
You might also be interested in:
|
||||
|
||||
- Join the [urbit-dev](https://groups.google.com/a/urbit.org/forum/#!forum/dev) mailing list.
|
||||
- [Ask us about Hoon School](mailto:support@urbit.org), a course we run to teach the Hoon programming language and Urbit application development.
|
||||
- Check out [good contributor issues](https://github.com/urbit/arvo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+contributor+issue%22).
|
||||
- Reach out to [support@urbit.org](mailto:support@urbit.org) to say hi and ask any questions you might have.
|
||||
- joining the [urbit-dev][list] mailing list.
|
||||
- [applying to Hoon School][mail], a course we run to teach the Hoon
|
||||
programming language and Urbit application development.
|
||||
|
||||
[list]: https://groups.google.com/a/urbit.org/forum/#!forum/dev
|
||||
[mail]: mailto:support@urbit.org
|
||||
[cont]: https://github.com/urbit/urbit/blob/master/CONTRIBUTING.md
|
||||
|
1218
pkg/arvo/app/chat-cli.hoon
Normal file
1218
pkg/arvo/app/chat-cli.hoon
Normal file
File diff suppressed because it is too large
Load Diff
354
pkg/arvo/app/chat-hook.hoon
Normal file
354
pkg/arvo/app/chat-hook.hoon
Normal file
@ -0,0 +1,354 @@
|
||||
:: chat-hook:
|
||||
:: mirror chat data from foreign to local based on read permissions
|
||||
:: allow sending chat messages to foreign paths based on write perms
|
||||
::
|
||||
/- *permission-store, *chat-hook
|
||||
/+ *chat-json
|
||||
|%
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ card
|
||||
$% [%diff [%chat-update chat-update]]
|
||||
[%quit ~]
|
||||
[%poke wire dock poke]
|
||||
[%pull wire dock ~]
|
||||
[%peer wire dock path]
|
||||
==
|
||||
::
|
||||
+$ state
|
||||
$% [%0 state-zero]
|
||||
==
|
||||
::
|
||||
+$ state-zero
|
||||
$: synced=(map path ship)
|
||||
boned=(map wire (list bone))
|
||||
==
|
||||
::
|
||||
+$ poke
|
||||
$% [%chat-action chat-action]
|
||||
[%permission-action permission-action]
|
||||
==
|
||||
::
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall state]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
?~ old
|
||||
:_ this
|
||||
[ost.bol %peer /permissions [our.bol %permission-store] /updates]~
|
||||
[~ this(+<+ u.old)]
|
||||
::
|
||||
++ poke-json
|
||||
|= jon=json
|
||||
^- (quip move _this)
|
||||
(poke-chat-action (json-to-action jon))
|
||||
::
|
||||
++ poke-chat-action
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
?> ?=(%message -.act)
|
||||
:: local
|
||||
:_ this
|
||||
?: (team:title our.bol src.bol)
|
||||
?. (~(has by synced) path.act)
|
||||
~
|
||||
=/ ship (~(got by synced) path.act)
|
||||
=/ appl ?:(=(ship our.bol) %chat-store %chat-hook)
|
||||
[ost.bol %poke / [ship appl] [%chat-action act]]~
|
||||
:: foreign
|
||||
=/ ship (~(get by synced) path.act)
|
||||
?~ ship
|
||||
~
|
||||
?. =(u.ship our.bol)
|
||||
~
|
||||
:: scry permissions to check if write is permitted
|
||||
?. (permitted-scry [(scot %p src.bol) %chat (weld path.act /write)])
|
||||
~
|
||||
=: author.envelope.act src.bol
|
||||
when.envelope.act now.bol
|
||||
==
|
||||
[ost.bol %poke / [our.bol %chat-store] [%chat-action act]]~
|
||||
::
|
||||
++ poke-chat-hook-action
|
||||
|= act=chat-hook-action
|
||||
^- (quip move _this)
|
||||
?- -.act
|
||||
%add-owned
|
||||
?> (team:title our.bol src.bol)
|
||||
=/ chat-path [%mailbox path.act]
|
||||
?: (~(has by synced) path.act)
|
||||
[~ this]
|
||||
=. synced (~(put by synced) path.act our.bol)
|
||||
:_ (track-bone chat-path)
|
||||
%+ weld
|
||||
[ost.bol %peer chat-path [our.bol %chat-store] chat-path]~
|
||||
(create-permission [%chat path.act] security.act)
|
||||
::
|
||||
%add-synced
|
||||
?> (team:title our.bol src.bol)
|
||||
=/ chat-path [%mailbox (scot %p ship.act) path.act]
|
||||
?: (~(has by synced) [(scot %p ship.act) path.act])
|
||||
[~ this]
|
||||
=. synced (~(put by synced) [(scot %p ship.act) path.act] ship.act)
|
||||
:_ (track-bone chat-path)
|
||||
[ost.bol %peer chat-path [ship.act %chat-hook] chat-path]~
|
||||
::
|
||||
%remove
|
||||
=/ ship (~(get by synced) path.act)
|
||||
?~ ship
|
||||
[~ this]
|
||||
?: &(=(u.ship our.bol) (team:title our.bol src.bol))
|
||||
:: delete one of our.bol own paths
|
||||
:_ %_ this
|
||||
synced (~(del by synced) path.act)
|
||||
boned (~(del by boned) [%mailbox path.act])
|
||||
==
|
||||
%- zing
|
||||
:~ (pull-wire [%mailbox path.act])
|
||||
(delete-permission [%chat path.act])
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib [%mailbox path.act] bol)
|
||||
|= [=bone *]
|
||||
[bone %quit ~]
|
||||
==
|
||||
?. |(=(u.ship src.bol) (team:title our.bol src.bol))
|
||||
:: if neither ship = source or source = us, do nothing
|
||||
[~ this]
|
||||
:: delete a foreign ship's path
|
||||
:- (pull-wire [%mailbox path.act])
|
||||
%_ this
|
||||
synced (~(del by synced) path.act)
|
||||
boned (~(del by boned) [%mailbox path.act])
|
||||
==
|
||||
==
|
||||
::
|
||||
++ peer-mailbox
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> ?=([* ^] pax)
|
||||
?> (~(has by synced) pax)
|
||||
:: scry permissions to check if read is permitted
|
||||
?> (permitted-scry [(scot %p src.bol) %chat (weld pax /read)])
|
||||
=/ box (chat-scry pax)
|
||||
?~ box !!
|
||||
:_ this
|
||||
[ost.bol %diff %chat-update [%create (slav %p i.pax) pax]]~
|
||||
::
|
||||
++ diff-permission-update
|
||||
|= [wir=wire diff=permission-update]
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
?- -.diff
|
||||
%create ~
|
||||
%delete ~
|
||||
%add (handle-permissions [%add path.diff who.diff])
|
||||
%remove (handle-permissions [%remove path.diff who.diff])
|
||||
==
|
||||
::
|
||||
++ handle-permissions
|
||||
|= [kind=?(%add %remove) pax=path who=(set ship)]
|
||||
^- (list move)
|
||||
?> ?=([* *] pax)
|
||||
?. =(%chat i.pax) ~
|
||||
:: check path to see if this is a %read permission
|
||||
?. =(%read (snag (dec (lent pax)) `(list @t)`pax))
|
||||
~
|
||||
=/ sup
|
||||
%- ~(gas by *(map [ship path] bone))
|
||||
%+ turn ~(tap by sup.bol)
|
||||
|=([=bone anchor=[ship path]] [anchor bone])
|
||||
%- zing
|
||||
%+ turn ~(tap in who)
|
||||
|= check-ship=ship
|
||||
?: (permitted-scry [(scot %p check-ship) pax])
|
||||
~
|
||||
:: if ship is not permitted, quit their subscription
|
||||
=/ mail-path
|
||||
(oust [(dec (lent t.pax)) (lent t.pax)] `(list @t)`t.pax)
|
||||
=/ bne (~(get by sup) [check-ship [%mailbox mail-path]])
|
||||
?~(bne ~ [u.bne %quit ~]~)
|
||||
::
|
||||
++ diff-chat-update
|
||||
|= [wir=wire diff=chat-update]
|
||||
^- (quip move _this)
|
||||
?: (team:title our.bol src.bol)
|
||||
(handle-local diff)
|
||||
(handle-foreign diff)
|
||||
::
|
||||
++ handle-local
|
||||
|= diff=chat-update
|
||||
^- (quip move _this)
|
||||
?- -.diff
|
||||
%keys [~ this]
|
||||
%config [~ this]
|
||||
%create [~ this]
|
||||
%read [~ this]
|
||||
%delete
|
||||
?. (~(has by synced) path.diff)
|
||||
[~ this]
|
||||
:_ this(synced (~(del by synced) path.diff))
|
||||
[ost.bol %pull [%mailbox path.diff] [our.bol %chat-store] ~]~
|
||||
::
|
||||
%message
|
||||
:_ this
|
||||
%+ turn (prey:pubsub:userlib [%mailbox path.diff] bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %diff [%chat-update diff]]
|
||||
==
|
||||
::
|
||||
++ handle-foreign
|
||||
|= diff=chat-update
|
||||
^- (quip move _this)
|
||||
?- -.diff
|
||||
%keys [~ this]
|
||||
%config [~ this]
|
||||
%read [~ this]
|
||||
%create
|
||||
:_ this
|
||||
?> ?=([* ^] path.diff)
|
||||
=/ shp (~(get by synced) path.diff)
|
||||
?~ shp ~
|
||||
?. =(src.bol u.shp) ~
|
||||
[(chat-poke [%create ship.diff t.path.diff])]~
|
||||
::
|
||||
%delete
|
||||
?> ?=([* ^] path.diff)
|
||||
=/ shp (~(get by synced) path.diff)
|
||||
?~ shp
|
||||
[~ this]
|
||||
?. =(u.shp src.bol)
|
||||
[~ this]
|
||||
:_ this(synced (~(del by synced) path.diff))
|
||||
:- (chat-poke diff)
|
||||
[ost.bol %pull [%mailbox path.diff] [src.bol %chat-hook] ~]~
|
||||
::
|
||||
%message
|
||||
:_ this
|
||||
?> ?=([* ^] path.diff)
|
||||
=/ shp (~(get by synced) path.diff)
|
||||
?~ shp ~
|
||||
?. =(src.bol u.shp) ~
|
||||
[(chat-poke diff)]~
|
||||
==
|
||||
::
|
||||
++ quit
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
~& chat-hook-quit+wir
|
||||
?: =(wir /permissions)
|
||||
:_ this
|
||||
[ost.bol %peer /permissions [our.bol %permission-store] /updates]~
|
||||
?> ?=([* ^] wir)
|
||||
?. (~(has by synced) t.wir)
|
||||
:: no-op
|
||||
[~ this]
|
||||
~& %chat-hook-resubscribe
|
||||
:_ (track-bone wir)
|
||||
[ost.bol %peer wir [(slav %p i.t.wir) %chat-hook] wir]~
|
||||
::
|
||||
++ reap
|
||||
|= [wir=wire saw=(unit tang)]
|
||||
^- (quip move _this)
|
||||
?~ saw
|
||||
[~ this]
|
||||
?> ?=(^ wir)
|
||||
:_ this(synced (~(del by synced) t.wir))
|
||||
%. ~
|
||||
%- slog
|
||||
:* leaf+"chat-hook failed subscribe on {(spud t.wir)}"
|
||||
leaf+"stack trace:"
|
||||
u.saw
|
||||
==
|
||||
::
|
||||
++ chat-poke
|
||||
|= act=chat-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %chat-store] [%chat-action act]]
|
||||
::
|
||||
++ permission-poke
|
||||
|= act=permission-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %permission-store] [%permission-action act]]
|
||||
::
|
||||
++ create-permission
|
||||
|= [pax=path sec=chat-security]
|
||||
^- (list move)
|
||||
=/ 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 move)
|
||||
=/ read-perm (weld pax /read)
|
||||
=/ write-perm (weld pax /write)
|
||||
:~ (permission-poke [%delete read-perm])
|
||||
(permission-poke [%delete write-perm])
|
||||
==
|
||||
::
|
||||
++ sec-to-perm
|
||||
|= [pax=path =kind]
|
||||
^- permission-action
|
||||
[%create pax kind *(set ship)]
|
||||
::
|
||||
++ chat-scry
|
||||
|= pax=path
|
||||
^- (unit mailbox)
|
||||
=. pax ;:(weld /=chat-store/(scot %da now.bol)/mailbox pax /noun)
|
||||
.^((unit mailbox) %gx pax)
|
||||
::
|
||||
++ permitted-scry
|
||||
|= pax=path
|
||||
^- ?
|
||||
.^(? %gx ;:(weld /=permission-store/(scot %da now.bol)/permitted pax /noun))
|
||||
::
|
||||
++ track-bone
|
||||
|= wir=wire
|
||||
^+ this
|
||||
=/ bnd (~(get by boned) wir)
|
||||
?^ bnd
|
||||
this(boned (~(put by boned) wir (snoc u.bnd ost.bol)))
|
||||
this(boned (~(put by boned) wir [ost.bol]~))
|
||||
::
|
||||
++ pull-wire
|
||||
|= pax=path
|
||||
^- (list move)
|
||||
?> ?=(^ pax)
|
||||
=/ bnd (~(get by boned) pax)
|
||||
?~ bnd ~
|
||||
=/ shp (~(get by synced) t.pax)
|
||||
?~ shp ~
|
||||
%+ turn u.bnd
|
||||
|= =bone
|
||||
^- move
|
||||
?: =(u.shp our.bol)
|
||||
[bone %pull pax [our.bol %chat-store] ~]
|
||||
[bone %pull pax [u.shp %chat-hook] ~]
|
||||
::
|
||||
--
|
237
pkg/arvo/app/chat-store.hoon
Normal file
237
pkg/arvo/app/chat-store.hoon
Normal file
@ -0,0 +1,237 @@
|
||||
:: chat-store: data store that holds linear sequences of chat messages
|
||||
::
|
||||
/+ *chat-json, *chat-eval
|
||||
|%
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ card
|
||||
$% [%diff diff]
|
||||
[%quit ~]
|
||||
==
|
||||
::
|
||||
+$ state
|
||||
$% [%0 state-zero]
|
||||
==
|
||||
::
|
||||
+$ state-zero
|
||||
$: =inbox
|
||||
==
|
||||
::
|
||||
+$ diff
|
||||
$% [%chat-initial inbox]
|
||||
[%chat-configs chat-configs]
|
||||
[%chat-update chat-update]
|
||||
==
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall state]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
[~ ?~(old this this(+<+ u.old))]
|
||||
::
|
||||
++ peek-x-all
|
||||
|= pax=path
|
||||
^- (unit (unit [%noun (map path mailbox)]))
|
||||
[~ ~ %noun inbox]
|
||||
::
|
||||
++ peek-x-configs
|
||||
|= pax=path
|
||||
^- (unit (unit [%noun chat-configs]))
|
||||
:^ ~ ~ %noun
|
||||
(inbox-to-configs inbox)
|
||||
::
|
||||
++ peek-x-keys
|
||||
|= pax=path
|
||||
^- (unit (unit [%noun (set path)]))
|
||||
[~ ~ %noun ~(key by inbox)]
|
||||
::
|
||||
++ peek-x-mailbox
|
||||
|= pax=path
|
||||
^- (unit (unit [%noun (unit mailbox)]))
|
||||
?~ pax ~
|
||||
=/ mailbox=(unit mailbox) (~(get by inbox) pax)
|
||||
[~ ~ %noun mailbox]
|
||||
::
|
||||
++ peek-x-config
|
||||
|= pax=path
|
||||
^- (unit (unit [%noun config]))
|
||||
?~ pax ~
|
||||
=/ mailbox (~(get by inbox) pax)
|
||||
?~ mailbox ~
|
||||
:^ ~ ~ %noun
|
||||
config.u.mailbox
|
||||
::
|
||||
++ peek-x-envelopes
|
||||
|= pax=path
|
||||
^- (unit (unit [%noun (list envelope)]))
|
||||
?+ pax ~
|
||||
[@ @ *]
|
||||
=/ mail-path t.t.pax
|
||||
=/ mailbox (~(get by inbox) mail-path)
|
||||
?~ mailbox
|
||||
[~ ~ %noun ~]
|
||||
=* envelopes envelopes.u.mailbox
|
||||
=/ sign-test=[?(%neg %pos) @]
|
||||
%- need
|
||||
%+ rush i.pax
|
||||
;~ pose
|
||||
%+ cook
|
||||
|= n=@
|
||||
[%neg n]
|
||||
;~(pfix hep dem:ag)
|
||||
::
|
||||
%+ cook
|
||||
|= n=@
|
||||
[%pos n]
|
||||
dem:ag
|
||||
==
|
||||
=* length length.config.u.mailbox
|
||||
=* start +.sign-test
|
||||
?: =(-.sign-test %neg)
|
||||
?: (gth start length)
|
||||
[~ ~ %noun envelopes]
|
||||
[~ ~ %noun (swag [(sub length start) start] envelopes)]
|
||||
::
|
||||
=/ end (slav %ud i.t.pax)
|
||||
?. (lte start end)
|
||||
~
|
||||
=. end ?:((lth end length) end length)
|
||||
[~ ~ %noun (swag [start (sub end start)] envelopes)]
|
||||
==
|
||||
::
|
||||
++ peer-keys
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:: we send the list of keys then send events when they change
|
||||
:_ this
|
||||
[ost.bol %diff %chat-update [%keys ~(key by inbox)]]~
|
||||
::
|
||||
++ peer-all
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:_ this
|
||||
[ost.bol %diff %chat-initial inbox]~
|
||||
::
|
||||
++ peer-configs
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:_ this
|
||||
[ost.bol %diff %chat-configs (inbox-to-configs inbox)]~
|
||||
::
|
||||
++ peer-updates
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:: we now proxy all events to this path
|
||||
[~ this]
|
||||
::
|
||||
++ peer-mailbox
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
?> (~(has by inbox) pax)
|
||||
=^ =ship pax
|
||||
?> ?=([* ^] pax)
|
||||
[(slav %p i.pax) t.pax]
|
||||
:_ this
|
||||
[ost.bol %diff %chat-update [%create ship pax]]~
|
||||
::
|
||||
++ poke-json
|
||||
|= jon=json
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
(poke-chat-action (json-to-action jon))
|
||||
::
|
||||
++ poke-chat-action
|
||||
|= action=chat-action
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
?- -.action
|
||||
%create (handle-create action)
|
||||
%delete (handle-delete action)
|
||||
%message (handle-message action)
|
||||
%read (handle-read action)
|
||||
==
|
||||
::
|
||||
++ handle-create
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
?> ?=(%create -.act)
|
||||
=/ pax [(scot %p ship.act) path.act]
|
||||
?: (~(has by inbox) pax)
|
||||
[~ this]
|
||||
:- (send-diff pax act)
|
||||
this(inbox (~(put by inbox) pax *mailbox))
|
||||
::
|
||||
++ handle-delete
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
?> ?=(%delete -.act)
|
||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||
?~ mailbox
|
||||
[~ this]
|
||||
:- (send-diff path.act act)
|
||||
this(inbox (~(del by inbox) path.act))
|
||||
::
|
||||
++ handle-message
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
?> ?=(%message -.act)
|
||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||
?~ mailbox
|
||||
[~ this]
|
||||
=* letter letter.envelope.act
|
||||
=? letter &(?=(%code -.letter) ?=(~ output.letter))
|
||||
=/ =hoon (ream expression.letter)
|
||||
letter(output (eval bol hoon))
|
||||
=: length.config.u.mailbox +(length.config.u.mailbox)
|
||||
number.envelope.act length.config.u.mailbox
|
||||
envelopes.u.mailbox (snoc envelopes.u.mailbox envelope.act)
|
||||
inbox (~(put by inbox) path.act u.mailbox)
|
||||
==
|
||||
:_ this(inbox inbox)
|
||||
(send-diff path.act act)
|
||||
::
|
||||
++ handle-read
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
?> ?=(%read -.act)
|
||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||
?~ mailbox
|
||||
[~ this]
|
||||
=: read.config.u.mailbox length.config.u.mailbox
|
||||
inbox (~(put by inbox) path.act u.mailbox)
|
||||
==
|
||||
:_ this(inbox inbox)
|
||||
(send-diff path.act act)
|
||||
::
|
||||
++ update-subscribers
|
||||
|= [pax=path act=chat-action]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %chat-update act]
|
||||
::
|
||||
++ send-diff
|
||||
|= [pax=path act=chat-action]
|
||||
^- (list move)
|
||||
%- zing
|
||||
:~ (update-subscribers /all act)
|
||||
(update-subscribers /updates act)
|
||||
(update-subscribers [%mailbox pax] act)
|
||||
?. |(=(%read -.act) =(%message -.act))
|
||||
~
|
||||
(update-subscribers /configs act)
|
||||
?. |(=(%create -.act) =(%delete -.act))
|
||||
~
|
||||
(update-subscribers /keys act)
|
||||
==
|
||||
::
|
||||
--
|
344
pkg/arvo/app/chat-view.hoon
Normal file
344
pkg/arvo/app/chat-view.hoon
Normal file
@ -0,0 +1,344 @@
|
||||
:: chat-view: sets up chat JS client, paginates data, and combines commands
|
||||
:: into semantic actions for the UI
|
||||
::
|
||||
/- *permission-store,
|
||||
*permission-hook,
|
||||
*group-store,
|
||||
*permission-group-hook,
|
||||
*chat-hook
|
||||
/+ *server, *chat-json
|
||||
/= index
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/index
|
||||
/| /html/
|
||||
/~ ~
|
||||
==
|
||||
/= tile-js
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/js/tile
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= script
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/js/index
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= style
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/css/index
|
||||
/| /css/
|
||||
/~ ~
|
||||
==
|
||||
/= chat-png
|
||||
/^ (map knot @)
|
||||
/: /===/app/chat/img /_ /png/
|
||||
::
|
||||
|%
|
||||
::
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ card
|
||||
$% [%http-response =http-event:http]
|
||||
[%connect wire binding:eyre term]
|
||||
[%peer wire dock path]
|
||||
[%poke wire dock poke]
|
||||
[%diff %json json]
|
||||
[%quit ~]
|
||||
==
|
||||
::
|
||||
+$ poke
|
||||
$% [%launch-action [@tas path @t]]
|
||||
[%chat-action chat-action]
|
||||
[%group-action group-action]
|
||||
[%chat-hook-action chat-hook-action]
|
||||
[%permission-hook-action permission-hook-action]
|
||||
[%permission-group-hook-action permission-group-hook-action]
|
||||
==
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall ?]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit ?)
|
||||
^- (quip move _this)
|
||||
?~ old
|
||||
:_ this
|
||||
:~ [ost.bol %peer / [our.bol %chat-store] /updates]
|
||||
[ost.bol %connect / [~ /'~chat'] %chat-view]
|
||||
(launch-poke [/configs '/~chat/js/tile.js'])
|
||||
==
|
||||
[~ this(+<+ u.old)]
|
||||
::
|
||||
++ bound
|
||||
|= [wir=wire success=? binding=binding:eyre]
|
||||
^- (quip move _this)
|
||||
[~ this]
|
||||
::
|
||||
++ poke-handle-http-request
|
||||
%- (require-authorization:app ost.bol move this)
|
||||
|= =inbound-request:eyre
|
||||
^- (quip move _this)
|
||||
::
|
||||
=+ url=(parse-request-line url.request.inbound-request)
|
||||
=/ name=@t
|
||||
=+ back-path=(flop site.url)
|
||||
?~ back-path
|
||||
''
|
||||
i.back-path
|
||||
?: =(name 'tile')
|
||||
[[ost.bol %http-response (js-response:app tile-js)]~ this]
|
||||
?+ site.url
|
||||
:_ this
|
||||
[ost.bol %http-response not-found:app]~
|
||||
::
|
||||
:: styling
|
||||
::
|
||||
[%'~chat' %css %index ~]
|
||||
:_ this
|
||||
[ost.bol %http-response (css-response:app style)]~
|
||||
::
|
||||
:: javascript
|
||||
::
|
||||
[%'~chat' %js %index ~]
|
||||
:_ this
|
||||
[ost.bol %http-response (js-response:app script)]~
|
||||
::
|
||||
:: images
|
||||
::
|
||||
[%'~chat' %img *]
|
||||
=/ img (as-octs:mimes:html (~(got by chat-png) `@ta`name))
|
||||
:_ this
|
||||
[ost.bol %http-response (png-response:app img)]~
|
||||
::
|
||||
[%'~chat' %paginate @t @t *]
|
||||
=/ start (need (rush i.t.t.site.url dem))
|
||||
=/ end (need (rush i.t.t.t.site.url dem))
|
||||
=/ pax t.t.t.t.site.url
|
||||
=/ envelopes (envelope-scry [(scot %ud start) (scot %ud end) pax])
|
||||
:_ this
|
||||
:~
|
||||
:+ ost.bol
|
||||
%http-response
|
||||
%- json-response:app
|
||||
%- json-to-octs
|
||||
%+ envelopes-update
|
||||
envelopes
|
||||
[start end pax]
|
||||
==
|
||||
::
|
||||
:: inbox page
|
||||
::
|
||||
[%'~chat' *]
|
||||
:_ this
|
||||
[ost.bol %http-response (html-response:app index)]~
|
||||
==
|
||||
::
|
||||
++ poke-json
|
||||
|= jon=json
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
(poke-chat-view-action (json-to-view-action jon))
|
||||
::
|
||||
++ poke-chat-view-action
|
||||
|= act=chat-view-action
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
?- -.act
|
||||
%create
|
||||
:: TODO: add invites
|
||||
=/ pax [(scot %p our.bol) path.act]
|
||||
=/ group-read=path [%chat (weld pax /read)]
|
||||
=/ group-write=path [%chat (weld pax /write)]
|
||||
:_ this
|
||||
%- zing
|
||||
:~ :~ (group-poke [%bundle group-read])
|
||||
(group-poke [%bundle group-write])
|
||||
(group-poke [%add read.act group-read])
|
||||
(group-poke [%add write.act group-write])
|
||||
(chat-poke [%create our.bol path.act])
|
||||
(chat-hook-poke [%add-owned pax security.act])
|
||||
==
|
||||
(create-security [%chat pax] security.act)
|
||||
:~ (permission-hook-poke [%add-owned group-read group-read])
|
||||
(permission-hook-poke [%add-owned group-write group-read])
|
||||
==
|
||||
==
|
||||
::
|
||||
%delete
|
||||
=/ group-read [%chat (weld path.act /read)]
|
||||
=/ group-write [%chat (weld path.act /write)]
|
||||
:_ this
|
||||
:~ (chat-hook-poke [%remove path.act])
|
||||
(permission-hook-poke [%remove group-read])
|
||||
(permission-hook-poke [%remove group-write])
|
||||
(group-poke [%unbundle group-read])
|
||||
(group-poke [%unbundle group-write])
|
||||
(chat-poke [%delete path.act])
|
||||
==
|
||||
::
|
||||
%join
|
||||
=/ group-read [%chat (scot %p ship.act) (weld path.act /read)]
|
||||
=/ group-write [%chat (scot %p ship.act) (weld path.act /write)]
|
||||
:_ this
|
||||
:~ (chat-hook-poke [%add-synced ship.act path.act])
|
||||
(permission-hook-poke [%add-synced ship.act group-write])
|
||||
(permission-hook-poke [%add-synced ship.act group-read])
|
||||
==
|
||||
::
|
||||
==
|
||||
::
|
||||
++ peer-primary
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:: create inbox with 100 messages max per mailbox and send that along
|
||||
:: then quit the subscription
|
||||
:_ this
|
||||
[ost.bol %diff %json (inbox-to-json (truncate-inbox all-scry))]~
|
||||
::
|
||||
++ peer-configs
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:_ this
|
||||
[ost.bol %diff %json *json]~
|
||||
::
|
||||
++ diff-chat-update
|
||||
|= [wir=wire upd=chat-update]
|
||||
^- (quip move _this)
|
||||
=/ updates-json (update-to-json upd)
|
||||
=/ configs-json (configs-to-json configs-scry)
|
||||
:_ this
|
||||
%+ weld
|
||||
%+ turn (prey:pubsub:userlib /primary bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %json updates-json]
|
||||
%+ turn (prey:pubsub:userlib /configs bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %json configs-json]
|
||||
::
|
||||
++ quit
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
[ost.bol %peer / [our.bol %chat-store] /updates]~
|
||||
::
|
||||
:: +utilities
|
||||
::
|
||||
++ launch-poke
|
||||
|= [=path =cord]
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %launch] [%launch-action %chat-view path cord]]
|
||||
::
|
||||
++ chat-poke
|
||||
|= act=chat-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %chat-store] [%chat-action act]]
|
||||
::
|
||||
++ group-poke
|
||||
|= act=group-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %group-store] [%group-action act]]
|
||||
::
|
||||
++ chat-hook-poke
|
||||
|= act=chat-hook-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %chat-hook] [%chat-hook-action act]]
|
||||
::
|
||||
++ permission-hook-poke
|
||||
|= act=permission-hook-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %permission-hook] [%permission-hook-action act]]
|
||||
::
|
||||
++ perm-group-hook-poke
|
||||
|= act=permission-group-hook-action
|
||||
^- move
|
||||
=/ pok [%permission-group-hook-action act]
|
||||
[ost.bol %poke / [our.bol %permission-group-hook] pok]
|
||||
::
|
||||
++ envelope-scry
|
||||
|= pax=path
|
||||
^- (list envelope)
|
||||
=. pax ;:(weld /=chat-store/(scot %da now.bol)/envelopes pax /noun)
|
||||
.^((list envelope) %gx pax)
|
||||
::
|
||||
++ all-scry
|
||||
^- inbox
|
||||
.^(inbox %gx /=chat-store/(scot %da now.bol)/all/noun)
|
||||
::
|
||||
++ configs-scry
|
||||
^- chat-configs
|
||||
.^(chat-configs %gx /=chat-store/(scot %da now.bol)/configs/noun)
|
||||
::
|
||||
++ create-security
|
||||
|= [pax=path sec=chat-security]
|
||||
^- (list move)
|
||||
=/ read (weld pax /read)
|
||||
=/ write (weld pax /write)
|
||||
?- sec
|
||||
%channel
|
||||
:~ (perm-group-hook-poke [%associate read [[read %black] ~ ~]])
|
||||
(perm-group-hook-poke [%associate write [[write %black] ~ ~]])
|
||||
==
|
||||
::
|
||||
%village
|
||||
:~ (perm-group-hook-poke [%associate read [[read %white] ~ ~]])
|
||||
(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] ~ ~]])
|
||||
==
|
||||
::
|
||||
==
|
||||
::
|
||||
++ envelopes-update
|
||||
|= [envelopes=(list envelope) start=@ud end=@ud pax=path]
|
||||
^- json
|
||||
=, enjs:format
|
||||
%+ frond %chat-update
|
||||
%- pairs
|
||||
:~
|
||||
:- %messages
|
||||
%- pairs
|
||||
:~ [%path (path pax)]
|
||||
[%start (numb start)]
|
||||
[%end (numb end)]
|
||||
[%envelopes [%a (turn envelopes enve)]]
|
||||
==
|
||||
==
|
||||
::
|
||||
++ truncate-envelopes
|
||||
|= envelopes=(list envelope)
|
||||
^- (list envelope)
|
||||
=/ length (lent envelopes)
|
||||
?: (lth length 100)
|
||||
envelopes
|
||||
(swag [(sub length 100) 100] envelopes)
|
||||
::
|
||||
++ truncate-inbox
|
||||
|= box=inbox
|
||||
^- inbox
|
||||
%- ~(run by box)
|
||||
|= mail=mailbox
|
||||
^- mailbox
|
||||
:- config.mail
|
||||
(truncate-envelopes envelopes.mail)
|
||||
::
|
||||
--
|
@ -1,614 +0,0 @@
|
||||
/- hall
|
||||
/+ *server, chat, hall-json
|
||||
/= index
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/index
|
||||
/| /html/
|
||||
/~ ~
|
||||
==
|
||||
/= tile-js
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/js/tile
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= script
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/js/index
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= style
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/chat/css/index
|
||||
/| /css/
|
||||
/~ ~
|
||||
==
|
||||
/= chat-png
|
||||
/^ (map knot @)
|
||||
/: /===/app/chat/img /_ /png/
|
||||
::
|
||||
=, chat
|
||||
::
|
||||
|%
|
||||
+$ state
|
||||
$% [%0 str=streams]
|
||||
==
|
||||
::
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ card
|
||||
$% [%http-response =http-event:http]
|
||||
[%connect wire binding:eyre term]
|
||||
[%peer wire dock path]
|
||||
[%quit ~]
|
||||
[%poke wire dock poke]
|
||||
[%peer wire dock path]
|
||||
[%pull wire dock ~]
|
||||
[%diff diff]
|
||||
==
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall state]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
:: +prep: set up the app, migrate the state
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
?^ old
|
||||
:_ this(+<+ u.old)
|
||||
[(launch-poke [/chattile '/~chat/js/tile.js'])]~
|
||||
::
|
||||
=/ inbox-path /circle/inbox/config/group
|
||||
::
|
||||
:_ this
|
||||
:* [ost.bol %connect / [~ /'~chat'] %chat]
|
||||
(launch-poke [/chattile '/~chat/js/tile.js'])
|
||||
(hall-peer /circle/(scot %p our.bol)/inbox/config/group inbox-path)
|
||||
(hall-peer /circles/(scot %p our.bol) /circles/(scot %p our.bol))
|
||||
(hall-source [our.bol %i])
|
||||
?: =((clan:title our.bol) %czar)
|
||||
~
|
||||
?: =(our.bol ~marzod)
|
||||
:- (hall-create %announcements 'Announcements from Tlon' %journal)
|
||||
[(hall-source [~marzod %announcements])]~
|
||||
?: =(our.bol ~dopzod)
|
||||
:- (hall-create %urbit-dev 'Chat about developing on Urbit' %channel)
|
||||
[(hall-create %urbit-help 'Help about Urbit' %channel)]~
|
||||
:~ (hall-create %hall-internal-announcements '' %village)
|
||||
(hall-source [our.bol %hall-internal-announcements])
|
||||
(hall-source [~marzod %announcements])
|
||||
==
|
||||
==
|
||||
::
|
||||
:: +peer-chattile: subscribe to data necessary for chat tile
|
||||
::
|
||||
++ peer-chattile
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
[ost.bol %diff %json (construct-tile-json str)]~
|
||||
::
|
||||
:: +peer-messages: subscribe to subset of messages and updates
|
||||
::
|
||||
++ peer-primary
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
=* messages messages.str
|
||||
:_ this
|
||||
:- [ost.bol %diff %chat-config str]
|
||||
%+ murn ~(tap by messages)
|
||||
|= [cir=circle:hall envelopes=(list envelope:hall)]
|
||||
^- (unit move)
|
||||
=/ length=@ (lent envelopes)
|
||||
=/ start=@
|
||||
?: (gte length 100)
|
||||
(sub length 100)
|
||||
0
|
||||
=/ end=@ length
|
||||
=/ offset=@ (sub end start)
|
||||
:- ~
|
||||
:* ost.bol
|
||||
%diff
|
||||
%chat-update
|
||||
[%messages cir start end (swag [start offset] envelopes)]
|
||||
==
|
||||
::
|
||||
:: +poke-chat: send a list of actions to hall
|
||||
::
|
||||
++ poke-chat-action
|
||||
|= act=action:chat
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
%+ turn lis.act
|
||||
|= hac=action:hall
|
||||
^- move
|
||||
[ost.bol %poke /p/(scot %da now.bol) [our.bol %hall] [%hall-action hac]]
|
||||
::
|
||||
:: +diff-hall-prize: handle full state initially handed to us by hall
|
||||
::
|
||||
++ diff-hall-prize
|
||||
|= [wir=wire piz=prize:hall]
|
||||
^- (quip move _this)
|
||||
?~ wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
?+ i.wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
::
|
||||
%circles
|
||||
?> ?=(%circles -.piz)
|
||||
=. str str(circles cis.piz)
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%circles cis.piz] str])
|
||||
::
|
||||
%circle
|
||||
?> ?=(%circle -.piz)
|
||||
?. =([our.bol &3:wir] [our.bol %inbox])
|
||||
::
|
||||
:: fill remote configs with message data
|
||||
::
|
||||
=* messages messages.str
|
||||
=/ circle [`@p`(slav %p &2:wir) &3:wir]
|
||||
=/ peers=(map circle:hall (set @p))
|
||||
%- ~(rep by rem.pes.piz)
|
||||
|= [[cir=circle:hall grp=group:hall] acc=(map circle:hall (set @p))]
|
||||
^+ acc
|
||||
(~(put by acc) cir (silt (turn ~(tap by grp) head)))
|
||||
::
|
||||
=. str
|
||||
%= str
|
||||
messages (~(put by messages) circle nes.piz)
|
||||
peers
|
||||
%- ~(uni by peers.str)
|
||||
(~(put by peers) circle ~(key by loc.pes.piz))
|
||||
==
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%messages circle 0 (lent messages) nes.piz] str])
|
||||
::
|
||||
:: fill inbox config and remote configs with prize data
|
||||
::
|
||||
=/ circles=(list circle:hall) (turn ~(tap in src.loc.cos.piz) head)
|
||||
::
|
||||
=/ peers=(map circle:hall (set @p))
|
||||
%- ~(rep by rem.pes.piz)
|
||||
|= [[cir=circle:hall grp=group:hall] acc=(map circle:hall (set @p))]
|
||||
^+ acc
|
||||
(~(put by acc) cir (silt (turn ~(tap by grp) head)))
|
||||
::
|
||||
:-
|
||||
%+ turn
|
||||
%~ tap in
|
||||
%- ~(del in (silt circles))
|
||||
[our.bol %inbox]
|
||||
|= cir=circle:hall
|
||||
%+ hall-peer
|
||||
/circle/(scot %p our.bol)/[nom.cir]/config/group
|
||||
/circle/[nom.cir]/config/group
|
||||
%= this
|
||||
inbox.str loc.cos.piz
|
||||
peers.str (~(put by peers) [our.bol %inbox] ~(key by loc.pes.piz))
|
||||
::
|
||||
configs.str
|
||||
%- ~(uni by configs.str)
|
||||
^- (map circle:hall (unit config:hall))
|
||||
(~(run by rem.cos.piz) some)
|
||||
::
|
||||
messages.str
|
||||
%- molt
|
||||
%+ turn circles
|
||||
|= cir=circle:hall
|
||||
^- [circle:hall (list envelope:hall)]
|
||||
[cir ~]
|
||||
==
|
||||
==
|
||||
::
|
||||
:: +diff-hall-rumor: handle updates to hall state
|
||||
::
|
||||
++ diff-hall-rumor
|
||||
|= [wir=wire rum=rumor:hall]
|
||||
^- (quip move _this)
|
||||
?~ wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
?+ i.wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
::
|
||||
%circles
|
||||
(handle-rumor-circles rum)
|
||||
::
|
||||
%circle
|
||||
(handle-rumor-circle wir rum)
|
||||
::
|
||||
==
|
||||
::
|
||||
:: +handle-rumor-circles
|
||||
::
|
||||
++ handle-rumor-circles
|
||||
|= rum=rumor:hall
|
||||
^- (quip move _this)
|
||||
?> ?=(%circles -.rum)
|
||||
=/ cis
|
||||
?: add.rum
|
||||
(~(put in circles.str) cir.rum)
|
||||
(~(del in circles.str) cir.rum)
|
||||
=. str
|
||||
%= str
|
||||
circles cis
|
||||
peers
|
||||
?: add.rum
|
||||
(~(put by peers.str) [our.bol cir.rum] ~)
|
||||
(~(del by peers.str) [our.bol cir.rum])
|
||||
==
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%circles cis] str])
|
||||
::
|
||||
++ handle-rumor-circle
|
||||
|= [wir=wire rum=rumor:hall]
|
||||
^- (quip move _this)
|
||||
?> ?=(%circle -.rum)
|
||||
?+ -.rum.rum
|
||||
[~ this]
|
||||
::
|
||||
:: %gram: new message
|
||||
::
|
||||
%gram
|
||||
(handle-rumor-circle-gram wir rum.rum)
|
||||
::
|
||||
:: status: status update
|
||||
::
|
||||
%status
|
||||
(handle-rumor-circle-status rum.rum)
|
||||
::
|
||||
:: %config: config has changed
|
||||
::
|
||||
%config
|
||||
?+ -.dif.rum.rum
|
||||
[~ this]
|
||||
::
|
||||
:: %full: set all of config without side effects
|
||||
::
|
||||
%full
|
||||
=* conf cof.dif.rum.rum
|
||||
=. configs.str (~(put by configs.str) cir.rum.rum `conf)
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%config cir.rum.rum conf] str])
|
||||
::
|
||||
:: %read: the read count of one of our configs has changed
|
||||
::
|
||||
%read
|
||||
(handle-rumor-circle-config-read rum.rum)
|
||||
::
|
||||
:: %source: the sources of our inbox have changed
|
||||
::
|
||||
%source
|
||||
(handle-rumor-circle-config-source rum.rum)
|
||||
::
|
||||
:: %remove: remove a circle
|
||||
::
|
||||
%remove
|
||||
=. str
|
||||
%= str
|
||||
configs (~(del by configs.str) cir.rum.rum)
|
||||
messages (~(del by messages.str) cir.rum.rum)
|
||||
peers (~(del by peers.str) cir.rum.rum)
|
||||
==
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%delete cir.rum.rum] str])
|
||||
::
|
||||
==
|
||||
==
|
||||
::
|
||||
++ handle-rumor-circle-gram
|
||||
|= [wir=wire sto=rumor-story:hall]
|
||||
^- (quip move _this)
|
||||
?> ?=(%gram -.sto)
|
||||
=* messages messages.str
|
||||
=/ circle [`@p`(slav %p &2:wir) &3:wir]
|
||||
=/ nes=(unit (list envelope:hall))
|
||||
(~(get by messages) circle)
|
||||
?~ nes
|
||||
[~ this]
|
||||
=. messages.str (~(put by messages) circle (snoc u.nes nev.sto))
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%message circle nev.sto] str])
|
||||
::
|
||||
++ handle-rumor-circle-status
|
||||
|= sto=rumor-story:hall
|
||||
^- (quip move _this)
|
||||
?> ?=(%status -.sto)
|
||||
=/ upeers=(unit (set @p)) (~(get by peers.str) cir.sto)
|
||||
?~ upeers
|
||||
[~ this]
|
||||
=/ peers=(set @p)
|
||||
?: =(%remove -.dif.sto)
|
||||
(~(del in u.upeers) who.sto)
|
||||
(~(put in u.upeers) who.sto)
|
||||
=. peers.str (~(put by peers.str) cir.sto peers)
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%peers cir.sto peers] str])
|
||||
::
|
||||
++ handle-rumor-circle-config-read
|
||||
|= sto=rumor-story:hall
|
||||
^- (quip move _this)
|
||||
?> ?=(%config -.sto)
|
||||
?> ?=(%read -.dif.sto)
|
||||
?: =(cir.sto [our.bol %inbox])
|
||||
:: ignore when cir.sto is inbox
|
||||
[~ this]
|
||||
=/ conf=(unit config:hall) (~(got by configs.str) cir.sto)
|
||||
?~ conf
|
||||
[~ this]
|
||||
=. red.u.conf red.dif.sto
|
||||
=. configs.str (~(put by configs.str) cir.sto conf)
|
||||
:_ this(str str)
|
||||
(send-chat-update [[%config cir.sto u.conf] str])
|
||||
::
|
||||
:: +handle-rumor-circle-config-source: on source, subscribe and add to inbox
|
||||
:: on remove source, send delete and remove data from state
|
||||
::
|
||||
++ handle-rumor-circle-config-source
|
||||
|= sto=rumor-story:hall
|
||||
^- (quip move _this)
|
||||
?> ?=(%config -.sto)
|
||||
?> ?=(%source -.dif.sto)
|
||||
?. =(cir.sto [our.bol %inbox])
|
||||
:: ignore when cir.sto is not inbox
|
||||
[~ this]
|
||||
=* circ cir.src.dif.sto
|
||||
=/ wir /circle/(scot %p hos.circ)/[nom.circ]/grams/0/config/group
|
||||
:: we've added a source to our inbox
|
||||
::
|
||||
?: add.dif.sto
|
||||
=. str
|
||||
%_ str
|
||||
src.inbox (~(put in src.inbox.str) src.dif.sto)
|
||||
::
|
||||
configs
|
||||
?: (~(has by configs.str) circ)
|
||||
configs.str
|
||||
(~(put by configs.str) circ ~)
|
||||
==
|
||||
::
|
||||
=/ pax /circle/[nom.circ]/grams/0/config/group
|
||||
:_ this(str str)
|
||||
:- [ost.bol %peer wir [hos.circ %hall] pax]
|
||||
(send-chat-update [[%inbox inbox.str] str])
|
||||
::
|
||||
=. src.inbox.str (~(del in src.inbox.str) src.dif.sto)
|
||||
:: we've removed a source from our inbox
|
||||
::
|
||||
=. str
|
||||
%= str
|
||||
inbox inbox.str
|
||||
::
|
||||
configs (~(del by configs.str) circ)
|
||||
messages (~(del by messages.str) circ)
|
||||
peers (~(del by peers.str) circ)
|
||||
==
|
||||
=/ fake=circle:hall
|
||||
[our.bol (crip (weld (trip 'hall-internal-') (trip nom.circ)))]
|
||||
::
|
||||
:_ this(str str)
|
||||
;: weld
|
||||
^- (list move)
|
||||
:: just forward the delete to our clients
|
||||
::
|
||||
?~ (~(get by configs.str) fake)
|
||||
[ost.bol %pull wir [hos.circ %hall] ~]~
|
||||
:: if we get a delete from another ship, delete our fake circle copy
|
||||
::
|
||||
:- [ost.bol %pull wir [hos.circ %hall] ~]
|
||||
[ost.bol %poke /f [our.bol %hall] [%hall-action [%delete nom.fake ~]]]~
|
||||
::
|
||||
(send-chat-update [[%inbox inbox.str] str])
|
||||
(send-chat-update [[%delete circ] str])
|
||||
==
|
||||
::
|
||||
:: +bound: lient tells us we successfully bound our server to the ~chat url
|
||||
::
|
||||
++ bound
|
||||
|= [wir=wire success=? binding=binding:eyre]
|
||||
^- (quip move _this)
|
||||
[~ this]
|
||||
::
|
||||
:: +poke-handle-http-request: serve pages from file system based on URl path
|
||||
::
|
||||
++ poke-handle-http-request
|
||||
%- (require-authorization:app ost.bol move this)
|
||||
|= =inbound-request:eyre
|
||||
^- (quip move _this)
|
||||
::
|
||||
=+ request-line=(parse-request-line url.request.inbound-request)
|
||||
=/ name=@t
|
||||
=+ back-path=(flop site.request-line)
|
||||
?~ back-path
|
||||
''
|
||||
i.back-path
|
||||
?: =(name 'tile')
|
||||
[[ost.bol %http-response (js-response:app tile-js)]~ this]
|
||||
?+ site.request-line
|
||||
:_ this
|
||||
[ost.bol %http-response not-found:app]~
|
||||
::
|
||||
:: styling
|
||||
::
|
||||
[%'~chat' %css %index ~]
|
||||
:_ this
|
||||
[ost.bol %http-response (css-response:app style)]~
|
||||
::
|
||||
:: javascript
|
||||
::
|
||||
[%'~chat' %js %index ~]
|
||||
:_ this
|
||||
[ost.bol %http-response (js-response:app script)]~
|
||||
::
|
||||
:: images
|
||||
::
|
||||
[%'~chat' %img *]
|
||||
=/ img (as-octs:mimes:html (~(got by chat-png) `@ta`name))
|
||||
:_ this
|
||||
[ost.bol %http-response (png-response:app img)]~
|
||||
::
|
||||
:: paginated message data
|
||||
::
|
||||
[%'~chat' %scroll @t @t @t @t ~]
|
||||
=/ cir [(slav %p &3:site.request-line) &4:site.request-line]
|
||||
=/ start=@ud (need (rush &5:site.request-line dem))
|
||||
=/ parsedend=@ud (need (rush &6:site.request-line dem))
|
||||
=* messages messages.str
|
||||
=/ envs=(unit (list envelope:hall)) (~(get by messages) cir)
|
||||
?~ envs
|
||||
[~ this]
|
||||
?: (gte start (lent u.envs))
|
||||
[~ this]
|
||||
=/ end=@
|
||||
?: (gte parsedend (lent u.envs))
|
||||
(dec (lent u.envs))
|
||||
parsedend
|
||||
=/ offset (sub end start)
|
||||
=/ jon
|
||||
%- msg-to-json
|
||||
:* %messages
|
||||
cir
|
||||
start
|
||||
end
|
||||
(swag [start offset] u.envs)
|
||||
==
|
||||
:_ this
|
||||
[ost.bol %http-response (json-response:app (json-to-octs jon))]~
|
||||
::
|
||||
::
|
||||
:: inbox page
|
||||
::
|
||||
[%'~chat' *]
|
||||
:_ this
|
||||
[ost.bol %http-response (html-response:app index)]~
|
||||
==
|
||||
::
|
||||
::
|
||||
:: +subscription-retry arms
|
||||
::
|
||||
::
|
||||
:: +reap: recieve acknowledgement for peer, retry on failure
|
||||
::
|
||||
++ reap
|
||||
|= [wir=wire err=(unit tang)]
|
||||
^- (quip move _this)
|
||||
?~ err
|
||||
[~ this]
|
||||
?~ wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
?+ i.wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
::
|
||||
%circle
|
||||
=/ shp=@p (slav %p &2:wir)
|
||||
=/ pat /circle/[&3:wir]/config/group
|
||||
?: =(&3:wir 'inbox')
|
||||
:_ this
|
||||
[ost.bol %peer wir [shp %hall] pat]~
|
||||
?: (~(has in src.inbox.str) [[shp &3:wir] ~])
|
||||
:_ this
|
||||
[ost.bol %peer wir [shp %hall] pat]~
|
||||
[~ this]
|
||||
::
|
||||
%circles
|
||||
:_ this
|
||||
[ost.bol %peer wir [our.bol %hall] wir]~
|
||||
==
|
||||
::
|
||||
:: +quit: subscription failed/quit at some point, retry
|
||||
::
|
||||
++ quit
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
?~ wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
?+ i.wir
|
||||
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
|
||||
::
|
||||
%circle
|
||||
=/ shp=@p (slav %p &2:wir)
|
||||
=/ pat /circle/[&3:wir]/config/group
|
||||
?: =(&3:wir 'inbox')
|
||||
:_ this
|
||||
[ost.bol %peer wir [shp %hall] pat]~
|
||||
?: (~(has in src.inbox.str) [[shp &3:wir] ~])
|
||||
:_ this
|
||||
[ost.bol %peer wir [shp %hall] pat]~
|
||||
[~ this]
|
||||
::
|
||||
%circles
|
||||
:_ this
|
||||
[ost.bol %peer wir [our.bol %hall] wir]~
|
||||
==
|
||||
::
|
||||
:: +utilities
|
||||
::
|
||||
::
|
||||
:: +send-chat-update: utility func for sending updates to all our subscribers
|
||||
::
|
||||
++ send-chat-update
|
||||
|= [upd=update str=streams]
|
||||
^- (list move)
|
||||
=/ jon-one (update-to-json upd)
|
||||
=/ jon-two (construct-tile-json str)
|
||||
::
|
||||
%+ weld
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib /primary bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %json jon-one]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib /chattile bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %json jon-two]
|
||||
::
|
||||
++ construct-tile-json
|
||||
|= str=streams
|
||||
^- json
|
||||
:- %o
|
||||
%- my
|
||||
:~ ['config' (config-to-json str)]
|
||||
::
|
||||
:- 'numbers'
|
||||
%- numbers-to-json
|
||||
^- (list [circle:hall @ud])
|
||||
%+ turn ~(tap by messages.str)
|
||||
|= [cir=circle:hall lis=(list envelope:hall)]
|
||||
^- [circle:hall @ud]
|
||||
?~ lis
|
||||
[cir 0]
|
||||
=/ last (snag (dec (lent lis)) `(list envelope:hall)`lis)
|
||||
[cir (add num.last 1)]
|
||||
==
|
||||
::
|
||||
++ launch-poke
|
||||
|= [=path =cord]
|
||||
^- move
|
||||
[ost.bol %poke /chat [our.bol %launch] [%launch-action %chat path cord]]
|
||||
::
|
||||
++ hall-peer
|
||||
|= [wir=wire pat=path]
|
||||
^- move
|
||||
[ost.bol %peer wir [our.bol %hall] pat]
|
||||
::
|
||||
++ hall-create
|
||||
|= [name=@tas description=@t =security:hall]
|
||||
^- move
|
||||
=/ poke [%hall-action [%create name description security]]
|
||||
[ost.bol %poke /chat [our.bol %hall] poke]
|
||||
::
|
||||
++ hall-source
|
||||
|= cir=circle:hall
|
||||
^- move
|
||||
=/ poke [%hall-action [%source %inbox %.y (silt [cir ~]~)]]
|
||||
[ost.bol %poke /chat [our.bol %hall] poke]
|
||||
::
|
||||
--
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -42,6 +42,11 @@
|
||||
:: %deed: deed ships based on json, assumes spawnable
|
||||
::
|
||||
[%deed deeds-json=cord]
|
||||
:: %invites: sendPoint for every ship in ship,ticket,owner file
|
||||
::
|
||||
:: to generate such a file, try |claz-invites ~star 1 10 %/out/txt
|
||||
::
|
||||
[%invites as-who=ship file=path]
|
||||
:: %lock-prep: prepare for lockup by transfering ships to the ceremony address
|
||||
::
|
||||
[%lock-prep what=(list ship)]
|
||||
@ -77,6 +82,8 @@
|
||||
[%transfer-ship who=ship to=address]
|
||||
[%set-transfer-proxy who=ship proxy=address]
|
||||
[%adopt who=ship]
|
||||
::
|
||||
[%send-point as=ship point=ship to=address]
|
||||
==
|
||||
::
|
||||
:: monadic structures
|
||||
@ -224,7 +231,8 @@
|
||||
::
|
||||
:: constants
|
||||
::
|
||||
++ ecliptic `address`0x6ac0.7b7c.4601.b5ce.11de.8dfe.6335.b871.c7c4.dd4d
|
||||
++ ecliptic 0x6ac0.7b7c.4601.b5ce.11de.8dfe.6335.b871.c7c4.dd4d
|
||||
++ delegated-sending 0xf790.8ab1.f1e3.52f8.3c5e.bc75.051c.0565.aeae.a5fb
|
||||
--
|
||||
::
|
||||
|_ [=bowl:gall state]
|
||||
@ -411,6 +419,7 @@
|
||||
?- -.batch
|
||||
%single [(single nonce network as +.batch) ~]
|
||||
%deed (deed nonce network as +.batch)
|
||||
%invites (invites nonce network as +.batch)
|
||||
%lock-prep (lock-prep nonce network as +.batch)
|
||||
%lock (lock nonce network as +.batch)
|
||||
::
|
||||
@ -473,7 +482,11 @@
|
||||
++ single
|
||||
|= [nonce=@ud =network as=address =call]
|
||||
^- transaction
|
||||
=- (do network nonce ecliptic -)
|
||||
=- (do network nonce contract data)
|
||||
^- [contract=address data=tape] ::TODO =;
|
||||
:- ?+ -.call ecliptic
|
||||
%send-point delegated-sending
|
||||
==
|
||||
?- -.call
|
||||
%create-galaxy (create-galaxy:dat +.call)
|
||||
%spawn (spawn:dat +.call)
|
||||
@ -484,6 +497,8 @@
|
||||
%transfer-ship (transfer-ship:dat +.call)
|
||||
%set-transfer-proxy (set-transfer-proxy:dat +.call)
|
||||
%adopt (adopt:dat +.call)
|
||||
::
|
||||
%send-point (send-point:dat +.call)
|
||||
==
|
||||
::
|
||||
++ deed
|
||||
@ -528,6 +543,33 @@
|
||||
(do network (add nonce (lent txs)) ecliptic dat)
|
||||
--
|
||||
::
|
||||
++ invites
|
||||
|= [nonce=@ud =network as=address as-who=ship file=path]
|
||||
^- (list transaction)
|
||||
=/ friends=(list [=ship @q =address])
|
||||
=+ txt=.^((list cord) %cx file)
|
||||
%+ turn txt
|
||||
|= line=cord
|
||||
~| line
|
||||
%+ rash line
|
||||
;~ (glue com)
|
||||
;~(pfix sig fed:ag)
|
||||
;~(pfix sig feq:ag)
|
||||
;~(pfix (jest '0x') hex)
|
||||
==
|
||||
=| txs=(list transaction)
|
||||
|-
|
||||
?~ friends (flop txs)
|
||||
=* friend i.friends
|
||||
=; tx=transaction
|
||||
$(txs [tx txs], friends t.friends)
|
||||
%- do
|
||||
:* network
|
||||
(add nonce (lent txs))
|
||||
delegated-sending
|
||||
(send-point:dat as-who [ship address]:friend)
|
||||
==
|
||||
::
|
||||
++ parse-registration
|
||||
|= reg=cord
|
||||
^- (list [=ship rights])
|
||||
@ -711,10 +753,13 @@
|
||||
++ set-dns-domains (enc set-dns-domains:cal)
|
||||
++ upgrade-to (enc upgrade-to:cal)
|
||||
++ transfer-ownership (enc transfer-ownership:cal)
|
||||
++ adopt (enc adopt:cal)
|
||||
++ adopt (enc adopt:cal)
|
||||
::
|
||||
++ register-linear (enc register-linear:cal)
|
||||
++ register-conditional (enc register-conditional:cal)
|
||||
++ deposit (enc deposit:cal)
|
||||
::
|
||||
++ send-point (enc send-point:cal)
|
||||
--
|
||||
::
|
||||
++ cal
|
||||
@ -863,6 +908,15 @@
|
||||
:~ [%address to]
|
||||
[%uint `@`star]
|
||||
==
|
||||
::
|
||||
++ send-point
|
||||
|= [as=ship point=ship to=address]
|
||||
^- call-data
|
||||
:- 'sendPoint(uint32,uint32,address)'
|
||||
:~ [%uint `@`as]
|
||||
[%uint `@`point]
|
||||
[%address to]
|
||||
==
|
||||
--
|
||||
::
|
||||
:: ++ peer-sole
|
||||
|
@ -39,7 +39,7 @@
|
||||
^- (quip move _this)
|
||||
?- -.act
|
||||
%add
|
||||
?. =(src.bol our.bol)
|
||||
?. (team:title our.bol src.bol)
|
||||
[~ this]
|
||||
=/ group-path [%group path.act]
|
||||
=/ group-wire [(scot %p ship.act) group-path]
|
||||
@ -55,7 +55,7 @@
|
||||
=/ ship (~(get by synced) path.act)
|
||||
?~ ship
|
||||
[~ this]
|
||||
?: &(=(u.ship our.bol) =(our.bol src.bol))
|
||||
?: &(=(u.ship our.bol) (team:title our.bol src.bol))
|
||||
:: delete one of our own paths
|
||||
=/ group-wire [(scot %p our.bol) %group path.act]
|
||||
:_ this(synced (~(del by synced) path.act))
|
||||
@ -66,22 +66,21 @@
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %quit ~]
|
||||
?: |(=(u.ship src.bol) =(our.bol src.bol))
|
||||
?: |(=(u.ship src.bol) (team:title our.bol src.bol))
|
||||
:: delete a foreign ship's path
|
||||
=/ group-wire [(scot %p u.ship) %group path.act]
|
||||
:_ this(synced (~(del by synced) path.act))
|
||||
(pull-wire group-wire path.act)
|
||||
:: don't allow
|
||||
[~ this]
|
||||
::
|
||||
==
|
||||
::
|
||||
++ peer-group
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?~ pax !!
|
||||
?. (~(has by synced) pax) !!
|
||||
=/ grp=(unit group) (group-scry pax)
|
||||
?> (~(has by synced) pax)
|
||||
=/ grp (group-scry pax)
|
||||
?~ grp !!
|
||||
:_ this
|
||||
[ost.bol %diff [%group-update [%path u.grp pax]]]~
|
||||
@ -89,7 +88,7 @@
|
||||
++ diff-group-update
|
||||
|= [wir=wire diff=group-update]
|
||||
^- (quip move _this)
|
||||
?: =(src.bol our.bol)
|
||||
?: (team:title our.bol src.bol)
|
||||
(handle-local diff)
|
||||
(handle-foreign diff)
|
||||
::
|
||||
@ -100,34 +99,17 @@
|
||||
%keys [~ this]
|
||||
%path [~ this]
|
||||
%bundle [~ this]
|
||||
%add
|
||||
:_ this
|
||||
%+ turn (prey:pubsub:userlib [%group pax.diff] bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %diff [%group-update diff]]
|
||||
::
|
||||
%remove
|
||||
:_ this
|
||||
%+ turn (prey:pubsub:userlib [%group pax.diff] bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %diff [%group-update diff]]
|
||||
%add [(update-subscribers [%group pax.diff] diff) this]
|
||||
%remove [(update-subscribers [%group pax.diff] diff) this]
|
||||
::
|
||||
%unbundle
|
||||
:_ this(synced (~(del by synced) pax.diff))
|
||||
%+ weld
|
||||
(update-subscribers [%group pax.diff] diff)
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib [%group pax.diff] bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %diff [%group-update diff]]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib [%group pax.diff] bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %quit ~]
|
||||
::
|
||||
==
|
||||
::
|
||||
++ handle-foreign
|
||||
@ -138,42 +120,31 @@
|
||||
%bundle [~ this]
|
||||
::
|
||||
%path
|
||||
?~ pax.diff
|
||||
[~ this]
|
||||
=/ ship (~(get by synced) pax.diff)
|
||||
?~ ship
|
||||
[~ this]
|
||||
?. =(src.bol u.ship)
|
||||
[~ this]
|
||||
:_ this
|
||||
?~ pax.diff ~
|
||||
=/ ship (~(get by synced) pax.diff)
|
||||
?~ ship ~
|
||||
?. =(src.bol u.ship) ~
|
||||
:~ (group-poke pax.diff [%unbundle pax.diff])
|
||||
(group-poke pax.diff [%bundle pax.diff])
|
||||
(group-poke pax.diff [%add members.diff pax.diff])
|
||||
==
|
||||
::
|
||||
%add
|
||||
?~ pax.diff
|
||||
[~ this]
|
||||
=/ ship (~(get by synced) pax.diff)
|
||||
?~ ship
|
||||
[~ this]
|
||||
?. =(src.bol u.ship)
|
||||
[~ this]
|
||||
:_ this
|
||||
:~ (group-poke pax.diff diff)
|
||||
==
|
||||
?~ pax.diff ~
|
||||
=/ ship (~(get by synced) pax.diff)
|
||||
?~ ship ~
|
||||
?. =(src.bol u.ship) ~
|
||||
[(group-poke pax.diff diff)]~
|
||||
::
|
||||
%remove
|
||||
?~ pax.diff
|
||||
[~ this]
|
||||
=/ ship (~(get by synced) pax.diff)
|
||||
?~ ship
|
||||
[~ this]
|
||||
?. =(src.bol u.ship)
|
||||
[~ this]
|
||||
:_ this
|
||||
:~ (group-poke pax.diff diff)
|
||||
==
|
||||
?~ pax.diff ~
|
||||
=/ ship (~(get by synced) pax.diff)
|
||||
?~ ship ~
|
||||
?. =(src.bol u.ship) ~
|
||||
[(group-poke pax.diff diff)]~
|
||||
::
|
||||
%unbundle
|
||||
?~ pax.diff
|
||||
@ -184,35 +155,30 @@
|
||||
?. =(src.bol u.ship)
|
||||
[~ this]
|
||||
:_ this(synced (~(del by synced) pax.diff))
|
||||
:~ (group-poke pax.diff diff)
|
||||
==
|
||||
::
|
||||
[(group-poke pax.diff diff)]~
|
||||
==
|
||||
::
|
||||
++ quit
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
=/ wir `(list @tas)`wir
|
||||
=/ =ship (slav %p &1:wir)
|
||||
=. wir ?^ wir t.wir ~
|
||||
=. wir ?^ wir t.wir ~
|
||||
?: (~(has by synced) wir)
|
||||
=/ group-path [%group wir]
|
||||
=/ group-wire [(scot %p ship) group-path]
|
||||
:_ (track-bone group-wire)
|
||||
[ost.bol %peer group-wire [ship %group-hook] group-path]~
|
||||
:: no-op
|
||||
[~ this]
|
||||
=^ =ship wir
|
||||
?> ?=([* ^] wir)
|
||||
[(slav %p i.wir) t.t.wir]
|
||||
?. (~(has by synced) wir)
|
||||
[~ this]
|
||||
=/ group-path [%group wir]
|
||||
=/ group-wire [(scot %p ship) group-path]
|
||||
:_ (track-bone group-wire)
|
||||
[ost.bol %peer group-wire [ship %group-hook] group-path]~
|
||||
::
|
||||
++ reap
|
||||
|= [wir=wire saw=(unit tang)]
|
||||
^- (quip move _this)
|
||||
?~ saw
|
||||
[~ this]
|
||||
=/ wir `(list @tas)`wir
|
||||
=/ =ship (slav %p &1:wir)
|
||||
=. wir ?^ wir t.wir ~
|
||||
=. wir ?^ wir t.wir ~
|
||||
=^ =ship wir
|
||||
?> ?=([* ^] wir)
|
||||
[(slav %p i.wir) t.t.wir]
|
||||
~& %insufficient-permissions-for-group
|
||||
[((slog u.saw) ~) this(synced (~(del by synced) wir))]
|
||||
::
|
||||
@ -224,12 +190,15 @@
|
||||
++ group-scry
|
||||
|= pax=path
|
||||
^- (unit group)
|
||||
=. pax ;: weld
|
||||
`path`/=group-store/(scot %da now.bol)
|
||||
pax
|
||||
`path`/noun
|
||||
==
|
||||
.^((unit group) %gx pax)
|
||||
.^((unit group) %gx ;:(weld /=group-store/(scot %da now.bol) pax /noun))
|
||||
::
|
||||
++ update-subscribers
|
||||
|= [pax=path diff=group-update]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %diff [%group-update diff]]
|
||||
::
|
||||
++ track-bone
|
||||
|= wir=wire
|
||||
|
@ -25,9 +25,7 @@
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
?~ old
|
||||
[~ this]
|
||||
[~ this(+<+ u.old)]
|
||||
[~ ?~(old this this(+<+ u.old))]
|
||||
::
|
||||
++ peek-x
|
||||
|= pax=path
|
||||
@ -40,7 +38,7 @@
|
||||
++ peer-all
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol) !!
|
||||
?> (team:title our.bol src.bol)
|
||||
:: we now proxy all events to this path
|
||||
:_ this
|
||||
[ost.bol %diff %group-initial groups]~
|
||||
@ -48,7 +46,7 @@
|
||||
++ peer-keys
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol) !!
|
||||
?> (team:title our.bol src.bol)
|
||||
:: we send the list of keys then send events when they change
|
||||
:_ this
|
||||
[ost.bol %diff %group-update [%keys ~(key by groups)]]~
|
||||
@ -56,17 +54,15 @@
|
||||
++ peer-group
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol) !!
|
||||
=/ grp=(unit group) (~(get by groups) pax)
|
||||
?~ grp !!
|
||||
?> (team:title our.bol src.bol)
|
||||
=/ grp (~(got by groups) pax)
|
||||
:_ this
|
||||
[ost.bol %diff %group-update [%path u.grp pax]]~
|
||||
[ost.bol %diff %group-update [%path grp pax]]~
|
||||
::
|
||||
++ poke-group-action
|
||||
|= action=group-action
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
?> (team:title our.bol src.bol)
|
||||
?- -.action
|
||||
%add (handle-add action)
|
||||
%remove (handle-remove action)
|
||||
@ -82,7 +78,7 @@
|
||||
[~ this]
|
||||
?. (~(has by groups) pax.act)
|
||||
[~ this]
|
||||
=/ members=group (~(got by groups) pax.act)
|
||||
=/ members (~(got by groups) pax.act)
|
||||
=. members (~(uni in members) members.act)
|
||||
?: =(members (~(got by groups) pax.act))
|
||||
[~ this]
|
||||
@ -126,26 +122,22 @@
|
||||
:- (send-diff pax.act act)
|
||||
this(groups (~(del by groups) pax.act))
|
||||
::
|
||||
++ send-diff
|
||||
|= [pax=path action=group-action]
|
||||
++ update-subscribers
|
||||
|= [pax=path act=group-action]
|
||||
^- (list move)
|
||||
;: weld
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib /all bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %group-update action]
|
||||
::
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib [%group pax] bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %group-update action]
|
||||
::
|
||||
^- (list move)
|
||||
?. |(=(%bundle -.action) =(%unbundle -.action))
|
||||
~
|
||||
%+ turn (prey:pubsub:userlib /keys bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %group-update action]
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %group-update act]
|
||||
::
|
||||
++ send-diff
|
||||
|= [pax=path act=group-action]
|
||||
^- (list move)
|
||||
%- zing
|
||||
:~ (update-subscribers /all act)
|
||||
(update-subscribers [%group pax] act)
|
||||
?. |(=(%bundle -.act) =(%unbundle -.act))
|
||||
~
|
||||
(update-subscribers /keys act)
|
||||
==
|
||||
::
|
||||
--
|
||||
|
@ -38,22 +38,18 @@
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
?~ old
|
||||
[~ this]
|
||||
[~ this(+<+ u.old)]
|
||||
[~ ?~(old this this(+<+ u.old))]
|
||||
::
|
||||
++ poke-json
|
||||
|= =json
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
?> (team:title our.bol src.bol)
|
||||
(poke-permission-group-hook-action (json-to-perm-group-hook-action json))
|
||||
::
|
||||
++ poke-permission-group-hook-action
|
||||
|= act=permission-group-hook-action
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
?> (team:title our.bol src.bol)
|
||||
?- -.act
|
||||
%associate (handle-associate group.act permissions.act)
|
||||
%dissociate (handle-dissociate group.act permissions.act)
|
||||
@ -64,25 +60,21 @@
|
||||
^- (quip move _this)
|
||||
=/ perms (~(get by relation) group)
|
||||
:: if relation does not exist, create it and subscribe.
|
||||
=/ permissions
|
||||
%- silt
|
||||
%+ turn ~(tap in permission-paths)
|
||||
|= [=path =kind]
|
||||
path
|
||||
=/ permissions=(set path)
|
||||
%- ~(run in permission-paths)
|
||||
|=([=path =kind] path)
|
||||
?~ perms
|
||||
=/ group-path [%group group]
|
||||
:_ this(relation (~(put by relation) group permissions))
|
||||
[ost.bol %peer group-path [our.bol %group-store] group-path]~
|
||||
::
|
||||
=. u.perms (~(uni in u.perms) permissions)
|
||||
:_ this(relation (~(put by relation) group u.perms))
|
||||
%+ weld
|
||||
%+ turn ~(tap in permissions)
|
||||
|= =path
|
||||
^- move
|
||||
(permission-poke path [%delete path])
|
||||
|=(=path (permission-poke path [%delete path]))
|
||||
%+ turn ~(tap in permission-paths)
|
||||
|= [=path =kind]
|
||||
^- move
|
||||
=/ pem *permission
|
||||
=. kind.pem kind
|
||||
(permission-poke path [%create path pem])
|
||||
@ -93,13 +85,12 @@
|
||||
=/ perms (~(get by relation) group)
|
||||
?~ perms
|
||||
[~ this]
|
||||
::
|
||||
=. permissions (~(del in u.perms) permissions)
|
||||
?~ permissions
|
||||
:_ this(relation (~(del by relation) group))
|
||||
:~ (group-pull [%group group])
|
||||
==
|
||||
:- ~
|
||||
this(relation (~(put by relation) group permissions))
|
||||
[(group-pull [%group group])]~
|
||||
[~ this(relation (~(put by relation) group permissions))]
|
||||
::
|
||||
++ diff-group-update
|
||||
|= [wir=wire diff=group-update]
|
||||
@ -117,7 +108,6 @@
|
||||
:_ this
|
||||
%+ turn ~(tap in u.perms)
|
||||
|= =path
|
||||
^- move
|
||||
(permission-poke path [%add path members.diff])
|
||||
::
|
||||
%add
|
||||
@ -128,7 +118,6 @@
|
||||
:_ this
|
||||
%+ turn ~(tap in u.perms)
|
||||
|= =path
|
||||
^- move
|
||||
(permission-poke path [%add path members.diff])
|
||||
::
|
||||
%remove
|
||||
@ -139,7 +128,6 @@
|
||||
:_ this
|
||||
%+ turn ~(tap in u.perms)
|
||||
|= =path
|
||||
^- move
|
||||
(permission-poke path [%remove path members.diff])
|
||||
::
|
||||
%unbundle
|
||||
@ -147,15 +135,12 @@
|
||||
=/ perms (~(get by relation) pax.diff)
|
||||
?~ perms
|
||||
:_ this(relation (~(del by relation) pax.diff))
|
||||
:~ (group-pull [%group pax.diff])
|
||||
==
|
||||
[(group-pull [%group pax.diff])]~
|
||||
:_ this(relation (~(del by relation) pax.diff))
|
||||
:- (group-pull [%group pax.diff])
|
||||
%+ turn ~(tap in u.perms)
|
||||
|= =path
|
||||
^- move
|
||||
(permission-poke path [%delete path])
|
||||
::
|
||||
==
|
||||
::
|
||||
++ quit
|
||||
@ -183,14 +168,4 @@
|
||||
^- move
|
||||
[ost.bol %pull [%group path] [our.bol %group-store] ~]
|
||||
::
|
||||
++ permission-scry
|
||||
|= pax=path
|
||||
^- (unit permission)
|
||||
=. pax ;: weld
|
||||
`path`/=permission-store/(scot %da now.bol)/permission
|
||||
pax
|
||||
`path`/noun
|
||||
==
|
||||
.^((unit permission) %gx pax)
|
||||
::
|
||||
--
|
||||
|
281
pkg/arvo/app/permission-hook.hoon
Normal file
281
pkg/arvo/app/permission-hook.hoon
Normal file
@ -0,0 +1,281 @@
|
||||
:: permission-hook: allows mirroring permissions between local and foreign
|
||||
:: ships. access control to an owned permission path is specified by the
|
||||
:: access-control path.
|
||||
::
|
||||
/- *permission-hook
|
||||
/+ *permission-json
|
||||
|%
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ card
|
||||
$% [%diff [%permission-update permission-update]]
|
||||
[%quit ~]
|
||||
[%poke wire dock [%permission-action permission-action]]
|
||||
[%pull wire dock ~]
|
||||
[%peer wire dock path]
|
||||
==
|
||||
::
|
||||
+$ state
|
||||
$% [%0 state-zero]
|
||||
==
|
||||
::
|
||||
+$ owner-access [ship=ship access-control=path]
|
||||
::
|
||||
+$ state-zero
|
||||
$: synced=(map path owner-access)
|
||||
access-control=(map path (set path))
|
||||
boned=(map wire (list bone))
|
||||
==
|
||||
::
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall state]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
[~ ?~(old this this(+<+ u.old))]
|
||||
::
|
||||
++ poke-permission-hook-action
|
||||
|= act=permission-hook-action
|
||||
^- (quip move _this)
|
||||
?- -.act
|
||||
%add-owned
|
||||
?> (team:title our.bol src.bol)
|
||||
?: (~(has by synced) owned.act)
|
||||
[~ this]
|
||||
=. synced (~(put by synced) owned.act [our.bol access.act])
|
||||
=/ access-paths
|
||||
?. (~(has by access-control) access.act)
|
||||
[owned.act ~ ~]
|
||||
(~(put in (~(got by access-control) access.act)) owned.act)
|
||||
=. access-control
|
||||
(~(put by access-control) access.act access-paths)
|
||||
=/ perm-path [%permission owned.act]
|
||||
:_ (track-bone perm-path)
|
||||
[ost.bol %peer perm-path [our.bol %permission-store] perm-path]~
|
||||
::
|
||||
%add-synced
|
||||
?> (team:title our.bol src.bol)
|
||||
?: (~(has by synced) path.act)
|
||||
[~ this]
|
||||
=. synced (~(put by synced) path.act [ship.act ~])
|
||||
=/ perm-path [%permission path.act]
|
||||
:_ (track-bone perm-path)
|
||||
[ost.bol %peer perm-path [ship.act %permission-hook] perm-path]~
|
||||
::
|
||||
%remove
|
||||
=/ owner-access=(unit owner-access) (~(get by synced) path.act)
|
||||
?~ owner-access
|
||||
[~ this]
|
||||
?: &(=(ship.u.owner-access our.bol) (team:title our.bol src.bol))
|
||||
:: delete one of our.bol own paths
|
||||
:_ %_ this
|
||||
synced (~(del by synced) path.act)
|
||||
boned (~(del by boned) [%permission path.act])
|
||||
::
|
||||
access-control
|
||||
(~(del by access-control) access-control.u.owner-access)
|
||||
==
|
||||
%- zing
|
||||
:~ (pull-wire [%permission path.act])
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib [%permission path.act] bol)
|
||||
|= [=bone *]
|
||||
[bone %quit ~]
|
||||
==
|
||||
?. |(=(ship.u.owner-access src.bol) (team:title our.bol src.bol))
|
||||
:: if neither ship = source or source = us, do nothing
|
||||
[~ this]
|
||||
:: delete a foreign ship's path
|
||||
:_ %_ this
|
||||
synced (~(del by synced) path.act)
|
||||
boned (~(del by boned) [%permission path.act])
|
||||
==
|
||||
(pull-wire [%permission path.act])
|
||||
==
|
||||
::
|
||||
++ peer-permission
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> ?=([* ^] pax)
|
||||
=/ =owner-access (~(got by synced) pax)
|
||||
?> =(our.bol ship.owner-access)
|
||||
:: scry permissions to check if subscriber is allowed
|
||||
?> (permitted-scry (scot %p src.bol) access-control.owner-access)
|
||||
=/ pem (permission-scry pax)
|
||||
:_ this
|
||||
[ost.bol %diff %permission-update [%create pax pem]]~
|
||||
::
|
||||
++ diff-permission-update
|
||||
|= [wir=wire diff=permission-update]
|
||||
^- (quip move _this)
|
||||
?: (team:title our.bol src.bol)
|
||||
(handle-local diff)
|
||||
(handle-foreign diff)
|
||||
::
|
||||
++ handle-local
|
||||
|= diff=permission-update
|
||||
^- (quip move _this)
|
||||
?- -.diff
|
||||
%create [~ this]
|
||||
%add (change-local-permission [%add path.diff who.diff])
|
||||
%remove (change-local-permission [%remove path.diff who.diff])
|
||||
::
|
||||
%delete
|
||||
?. (~(has by synced) path.diff)
|
||||
[~ this]
|
||||
:_ this(synced (~(del by synced) path.diff))
|
||||
[ost.bol %pull [%permission path.diff] [our.bol %permission-store] ~]~
|
||||
==
|
||||
::
|
||||
++ change-local-permission
|
||||
|= [kind=?(%add %remove) pax=path who=(set ship)]
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
%+ weld
|
||||
?- kind
|
||||
%add (update-subscribers [%permission pax] [%add pax who])
|
||||
%remove (update-subscribers [%permission pax] [%remove pax who])
|
||||
==
|
||||
=/ access-paths=(unit (set path)) (~(get by access-control) pax)
|
||||
:: check if this path changes the access permissions for other paths
|
||||
?~ access-paths
|
||||
~
|
||||
(quit-subscriptions kind pax who u.access-paths)
|
||||
::
|
||||
++ handle-foreign
|
||||
|= diff=permission-update
|
||||
^- (quip move _this)
|
||||
?- -.diff
|
||||
%create (change-foreign-permission path.diff diff)
|
||||
%add (change-foreign-permission path.diff diff)
|
||||
%remove (change-foreign-permission path.diff diff)
|
||||
::
|
||||
%delete
|
||||
?> ?=([* ^] path.diff)
|
||||
=/ owner-access=(unit owner-access) (~(get by synced) path.diff)
|
||||
?~ owner-access
|
||||
[~ this]
|
||||
?. =(ship.u.owner-access src.bol)
|
||||
[~ this]
|
||||
:_ this(synced (~(del by synced) path.diff))
|
||||
:~ (permission-poke diff)
|
||||
[ost.bol %pull [%permission path.diff] [src.bol %permission-hook] ~]
|
||||
==
|
||||
==
|
||||
::
|
||||
++ change-foreign-permission
|
||||
|= [pax=path diff=permission-update]
|
||||
^- (quip move _this)
|
||||
?> ?=([* ^] pax)
|
||||
=/ owner-access=(unit owner-access) (~(get by synced) pax)
|
||||
:_ this
|
||||
?~ owner-access ~
|
||||
?. =(src.bol ship.u.owner-access) ~
|
||||
[(permission-poke diff)]~
|
||||
::
|
||||
++ quit-subscriptions
|
||||
|= [kind=?(%add %remove) pax=path who=(set ship) access-paths=(set path)]
|
||||
^- (list move)
|
||||
=/ perm (permission-scry pax)
|
||||
?. ?|
|
||||
?&(=(kind.perm %black) =(kind %add))
|
||||
?&(=(kind.perm %white) =(kind %remove))
|
||||
==
|
||||
:: if allow, do nothing
|
||||
~
|
||||
=/ sup
|
||||
%- ~(gas by *(map [ship path] bone))
|
||||
%+ turn ~(tap by sup.bol)
|
||||
|=([=bone anchor=[ship path]] [anchor bone])
|
||||
:: if ban, iterate through
|
||||
:: all ships that have been banned
|
||||
:: and all affected paths that have had their permissions changed
|
||||
:: then quit their subscriptions
|
||||
::
|
||||
%- zing
|
||||
%+ turn ~(tap in who)
|
||||
|= check-ship=ship
|
||||
^- (list move)
|
||||
%+ murn ~(tap in access-paths)
|
||||
|= access-path=path
|
||||
^- (unit move)
|
||||
=/ bne (~(get by sup) [check-ship [%permission access-path]])
|
||||
?~(bne ~ `[u.bne %quit ~])
|
||||
::
|
||||
++ quit
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
~& permission-hook-quit+wir
|
||||
?> ?=([* ^] wir)
|
||||
?. (~(has by synced) t.wir)
|
||||
:: no-op
|
||||
[~ this]
|
||||
=/ =owner-access (~(got by synced) t.wir)
|
||||
~& %permission-hook-resubscribe
|
||||
:_ (track-bone wir)
|
||||
[ost.bol %peer wir [ship.owner-access %permission-hook] wir]~
|
||||
::
|
||||
++ reap
|
||||
|= [wir=wire saw=(unit tang)]
|
||||
^- (quip move _this)
|
||||
?~ saw
|
||||
[~ this]
|
||||
?> ?=(^ wir)
|
||||
:_ this(synced (~(del by synced) t.wir))
|
||||
%. ~
|
||||
%- slog
|
||||
:* leaf+"permission-hook failed subscribe on {(spud t.wir)}"
|
||||
leaf+"stack trace:"
|
||||
u.saw
|
||||
==
|
||||
::
|
||||
++ permission-scry
|
||||
|= pax=path
|
||||
^- permission
|
||||
=. pax ;:(weld /=permission-store/(scot %da now.bol)/permission pax /noun)
|
||||
(need .^((unit permission) %gx pax))
|
||||
::
|
||||
++ permitted-scry
|
||||
|= pax=path
|
||||
^- ?
|
||||
.^(? %gx ;:(weld /=permission-store/(scot %da now.bol)/permitted pax /noun))
|
||||
::
|
||||
++ permission-poke
|
||||
|= act=permission-action
|
||||
^- move
|
||||
[ost.bol %poke / [our.bol %permission-store] [%permission-action act]]
|
||||
::
|
||||
++ update-subscribers
|
||||
|= [pax=path upd=permission-update]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %permission-update upd]
|
||||
::
|
||||
++ track-bone
|
||||
|= wir=wire
|
||||
^+ this
|
||||
=/ bnd (~(get by boned) wir)
|
||||
?^ bnd
|
||||
this(boned (~(put by boned) wir (snoc u.bnd ost.bol)))
|
||||
this(boned (~(put by boned) wir [ost.bol]~))
|
||||
::
|
||||
++ pull-wire
|
||||
|= pax=path
|
||||
^- (list move)
|
||||
?> ?=([* ^] pax)
|
||||
=/ bnd (~(get by boned) pax)
|
||||
?~ bnd ~
|
||||
=/ owner-access=(unit owner-access) (~(get by synced) t.pax)
|
||||
?~ owner-access ~
|
||||
%+ turn u.bnd
|
||||
|= =bone
|
||||
?: =(ship.u.owner-access our.bol)
|
||||
[bone %pull pax [our.bol %permission-store] ~]
|
||||
[bone %pull pax [ship.u.owner-access %permission-hook] ~]
|
||||
::
|
||||
--
|
@ -25,17 +25,24 @@
|
||||
++ peer-all
|
||||
|= =path
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol) !!
|
||||
?> (team:title our.bol src.bol)
|
||||
:: we now proxy all events to this path
|
||||
:_ this
|
||||
[ost.bol %diff %permission-initial permissions]~
|
||||
::
|
||||
++ peer-updates
|
||||
|= =path
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:: we now proxy all events to this path
|
||||
[~ this]
|
||||
::
|
||||
++ peer-permission
|
||||
|= =path
|
||||
^- (quip move _this)
|
||||
?~ path !!
|
||||
?. =(src.bol our.bol) !!
|
||||
?. (~(has by permissions) path) !!
|
||||
?> (team:title our.bol src.bol)
|
||||
?> (~(has by permissions) path)
|
||||
:_ this
|
||||
[ost.bol %diff %permission-update [%create path (~(got by permissions) path)]]~
|
||||
::
|
||||
@ -67,8 +74,7 @@
|
||||
++ poke-permission-action
|
||||
|= action=permission-action
|
||||
^- (quip move _this)
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
?> (team:title our.bol src.bol)
|
||||
?- -.action
|
||||
%add (handle-add action)
|
||||
%remove (handle-remove action)
|
||||
@ -159,20 +165,20 @@
|
||||
(handle-add [%add +.act])
|
||||
(handle-remove [%remove +.act])
|
||||
::
|
||||
++ send-diff
|
||||
|= [pax=path update=permission-update]
|
||||
++ update-subscribers
|
||||
|= [pax=path upd=permission-update]
|
||||
^- (list move)
|
||||
;: weld
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib /all bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %permission-update update]
|
||||
::
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib [%permission pax] bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %permission-update update]
|
||||
::
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %permission-update upd]
|
||||
::
|
||||
++ send-diff
|
||||
|= [pax=path upd=permission-update]
|
||||
^- (list move)
|
||||
%- zing
|
||||
:~ (update-subscribers /all upd)
|
||||
(update-subscribers /updates upd)
|
||||
(update-subscribers [%permission pax] upd)
|
||||
==
|
||||
::
|
||||
--
|
||||
|
41
pkg/arvo/gen/hood/claz-invites.hoon
Normal file
41
pkg/arvo/gen/hood/claz-invites.hoon
Normal file
@ -0,0 +1,41 @@
|
||||
:: |claz-invites: generate invite tickets for star's children
|
||||
::
|
||||
:: writes to .txt with lines in the format ~planet,~ticket,0xaddress
|
||||
::
|
||||
:: eg: |claz-invites ~marzod 1 10 %/example-invites/txt
|
||||
::
|
||||
/+ keygen
|
||||
=, ethereum
|
||||
::
|
||||
:- %say
|
||||
|= $: [now=@da eny=@uvJ =beak]
|
||||
[star=ship min-child=@ud max-child=@ud out=path ~]
|
||||
~
|
||||
==
|
||||
?: (gth min-child max-child)
|
||||
~| [%weird-range min=min-child max=max-child]
|
||||
!!
|
||||
?: (gth max-child 0xffff)
|
||||
~| [%max-beyond-planet-space max-child]
|
||||
!!
|
||||
~& 'patience, slow derivation...'
|
||||
:- %kiln-info
|
||||
:- "wrote generated invites to {(spud out)}"
|
||||
%- some
|
||||
%+ foal:space:userlib out
|
||||
:- %txt
|
||||
!>
|
||||
%+ turn (gulf min-child max-child)
|
||||
|= child=@ud
|
||||
=/ who=ship (cat 4 star child)
|
||||
=/ ticket=@q (end 3 8 (shas who eny))
|
||||
=/ owner=address
|
||||
=< addr.keys
|
||||
::NOTE ~zod because invite wallet convention
|
||||
(ownership-wallet-from-ticket:keygen ~zod 8^ticket ~)
|
||||
%- crip
|
||||
;: weld
|
||||
(scow %p who) ","
|
||||
(slag 1 (scow %q ticket)) ","
|
||||
(address-to-hex:ethereum owner)
|
||||
==
|
245
pkg/arvo/lib/chat-json.hoon
Normal file
245
pkg/arvo/lib/chat-json.hoon
Normal file
@ -0,0 +1,245 @@
|
||||
/- *chat-store, *chat-view
|
||||
/+ chat-eval
|
||||
|%
|
||||
::
|
||||
++ slan |=(mod/@tas |=(txt/@ta (need (slaw mod txt))))
|
||||
::
|
||||
++ seri ::: serial
|
||||
=, dejs:format
|
||||
^- $-(json serial)
|
||||
(cu (slan %uv) so)
|
||||
::
|
||||
++ re :: recursive reparsers
|
||||
|* {gar/* sef/_|.(fist:dejs-soft:format)}
|
||||
|= jon/json
|
||||
^- (unit _gar)
|
||||
=- ~! gar ~! (need -) -
|
||||
((sef) jon)
|
||||
::
|
||||
++ dank :: tank
|
||||
^- $-(json (unit tank))
|
||||
=, ^? dejs-soft:format
|
||||
%+ re *tank |. ~+
|
||||
%- of :~
|
||||
leaf+sa
|
||||
palm+(ot style+(ot mid+sa cap+sa open+sa close+sa ~) lines+(ar dank) ~)
|
||||
rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~)
|
||||
==
|
||||
::
|
||||
++ eval ::: %exp speech
|
||||
::: extract contents of an %exp speech, evaluating
|
||||
::: the {exp} if there is no {res} yet.
|
||||
::
|
||||
|= a=json
|
||||
^- [cord (list tank)]
|
||||
=, ^? dejs-soft:format
|
||||
=+ exp=((ot expression+so ~) a)
|
||||
%- need
|
||||
?~ exp [~ '' ~]
|
||||
:+ ~ u.exp
|
||||
::NOTE when sending, if output is an empty list, chat-store will evaluate
|
||||
(fall ((ot output+(ar dank) ~) a) ~)
|
||||
::
|
||||
++ lett
|
||||
|= =letter
|
||||
^- json
|
||||
=, enjs:format
|
||||
?- -.letter
|
||||
%text
|
||||
(frond %text s+text.letter)
|
||||
::
|
||||
%url
|
||||
(frond %url s+url.letter)
|
||||
::
|
||||
%code
|
||||
%+ frond %code
|
||||
%- pairs
|
||||
:~ [%expression s+expression.letter]
|
||||
[%output a+(turn output.letter tank)]
|
||||
==
|
||||
::
|
||||
%me
|
||||
(frond %me s+narrative.letter)
|
||||
::
|
||||
==
|
||||
::
|
||||
++ enve
|
||||
|= =envelope
|
||||
^- json
|
||||
=, enjs:format
|
||||
%- pairs
|
||||
:~ [%uid s+(scot %uv uid.envelope)]
|
||||
[%number (numb number.envelope)]
|
||||
[%author (ship author.envelope)]
|
||||
[%when (time when.envelope)]
|
||||
[%letter (lett letter.envelope)]
|
||||
==
|
||||
::
|
||||
++ conf
|
||||
|= =config
|
||||
^- json
|
||||
=, enjs:format
|
||||
%- pairs
|
||||
:~ [%length (numb length.config)]
|
||||
[%read (numb read.config)]
|
||||
==
|
||||
::
|
||||
++ inbox-to-configs
|
||||
|= =inbox
|
||||
^- chat-configs
|
||||
%- ~(run by inbox)
|
||||
|= =mailbox
|
||||
^- config
|
||||
config.mailbox
|
||||
::
|
||||
++ configs-to-json
|
||||
|= cfg=chat-configs
|
||||
=, enjs:format
|
||||
^- json
|
||||
%+ frond %chat-configs
|
||||
%- pairs
|
||||
%+ turn ~(tap by cfg)
|
||||
|= [pax=^path =config]
|
||||
^- [cord json]
|
||||
[(spat pax) (conf config)]
|
||||
::
|
||||
++ inbox-to-json
|
||||
|= box=inbox
|
||||
=, enjs:format
|
||||
^- json
|
||||
%+ frond %chat-initial
|
||||
%- pairs
|
||||
%+ turn ~(tap by box)
|
||||
|= [pax=^path =mailbox]
|
||||
^- [cord json]
|
||||
:- (spat pax)
|
||||
%- pairs
|
||||
:~ [%envelopes [%a (turn envelopes.mailbox enve)]]
|
||||
[%config (conf config.mailbox)]
|
||||
==
|
||||
::
|
||||
++ update-to-json
|
||||
|= upd=chat-update
|
||||
=, enjs:format
|
||||
^- json
|
||||
%+ frond %chat-update
|
||||
%- pairs
|
||||
:~
|
||||
?: =(%message -.upd)
|
||||
?> ?=(%message -.upd)
|
||||
:- %message
|
||||
%- pairs
|
||||
:~ [%path (path path.upd)]
|
||||
[%envelope (enve envelope.upd)]
|
||||
==
|
||||
?: =(%read -.upd)
|
||||
?> ?=(%read -.upd)
|
||||
[%read (pairs [%path (path path.upd)]~)]
|
||||
?: =(%create -.upd)
|
||||
?> ?=(%create -.upd)
|
||||
:- %create
|
||||
%- pairs
|
||||
:~ [%ship (ship ship.upd)]
|
||||
[%path (path path.upd)]
|
||||
==
|
||||
?: =(%delete -.upd)
|
||||
?> ?=(%delete -.upd)
|
||||
[%delete (pairs [%path (path path.upd)]~)]
|
||||
?: =(%config -.upd)
|
||||
?> ?=(%config -.upd)
|
||||
:- %config
|
||||
%- pairs
|
||||
:~ [%path (path path.upd)]
|
||||
[%config (conf config.upd)]
|
||||
==
|
||||
[*@t *^json]
|
||||
==
|
||||
::
|
||||
++ json-to-action
|
||||
|= jon=json
|
||||
^- chat-action
|
||||
=, dejs:format
|
||||
=< (parse-json jon)
|
||||
|%
|
||||
++ parse-json
|
||||
%- of
|
||||
:~ [%create create]
|
||||
[%delete delete]
|
||||
[%message message]
|
||||
[%read read]
|
||||
==
|
||||
::
|
||||
++ create
|
||||
%- ot
|
||||
:~ [%ship (su ;~(pfix sig fed:ag))]
|
||||
[%path pa]
|
||||
==
|
||||
::
|
||||
++ delete
|
||||
(ot [%path pa]~)
|
||||
::
|
||||
++ message
|
||||
%- ot
|
||||
:~ [%path pa]
|
||||
[%envelope envelope]
|
||||
==
|
||||
::
|
||||
++ read
|
||||
(ot [%path pa] ~)
|
||||
::
|
||||
++ envelope
|
||||
%- ot
|
||||
:~ [%uid seri]
|
||||
[%number ni]
|
||||
[%author (su ;~(pfix sig fed:ag))]
|
||||
[%when di]
|
||||
[%letter letter]
|
||||
==
|
||||
::
|
||||
++ letter
|
||||
%- of
|
||||
:~ [%text so]
|
||||
[%url so]
|
||||
[%code eval]
|
||||
[%me so]
|
||||
==
|
||||
::
|
||||
--
|
||||
::
|
||||
++ json-to-view-action
|
||||
|= jon=json
|
||||
^- chat-view-action
|
||||
=, dejs:format
|
||||
=< (parse-json jon)
|
||||
|%
|
||||
++ parse-json
|
||||
%- of
|
||||
:~ [%create create]
|
||||
[%delete delete]
|
||||
[%join join]
|
||||
==
|
||||
::
|
||||
++ create
|
||||
%- ot
|
||||
:~ [%path pa]
|
||||
[%security sec]
|
||||
[%read (as (su ;~(pfix sig fed:ag)))]
|
||||
[%write (as (su ;~(pfix sig fed:ag)))]
|
||||
==
|
||||
::
|
||||
++ delete
|
||||
(ot [%path pa]~)
|
||||
::
|
||||
++ join
|
||||
%- ot
|
||||
:~ [%ship (su ;~(pfix sig fed:ag))]
|
||||
[%path pa]
|
||||
==
|
||||
::
|
||||
++ sec
|
||||
=, dejs:format
|
||||
^- $-(json chat-security)
|
||||
(su (perk %channel %village %journal %mailbox ~))
|
||||
--
|
||||
--
|
||||
|
16
pkg/arvo/lib/chat/eval.hoon
Normal file
16
pkg/arvo/lib/chat/eval.hoon
Normal file
@ -0,0 +1,16 @@
|
||||
|%
|
||||
++ eval
|
||||
|= [=bowl:gall =hoon]
|
||||
^- (list tank)
|
||||
=/ subj=[our=@p now=@da eny=@uvJ]
|
||||
:+ our.bowl
|
||||
now.bowl
|
||||
(shaz (cat 3 (mix [now eny]:bowl) %eny))
|
||||
::
|
||||
;; (list tank)
|
||||
=< +>
|
||||
%+ mong
|
||||
:- mute
|
||||
|.([(sell (slap (slop !>(subj) !>(..zuse)) hoon))]~)
|
||||
|=(^ ~)
|
||||
--
|
@ -76,52 +76,43 @@
|
||||
|= [our/ship lit/?]
|
||||
%- ~(gas in *(set well:gall))
|
||||
^- (list well:gall)
|
||||
?: lit
|
||||
:~ [%home %dojo]
|
||||
[%home %azimuth-tracker]
|
||||
==
|
||||
=+ myr=(clan:title our)
|
||||
:: boot all default apps off the home desk
|
||||
::
|
||||
?: ?=($pawn myr)
|
||||
:~ [%home %lens]
|
||||
[%base %hall]
|
||||
[%base %talk]
|
||||
[%base %dojo]
|
||||
[%base %modulo]
|
||||
[%home %launch]
|
||||
[%home %chat]
|
||||
[%home %publish]
|
||||
[%home %clock]
|
||||
[%home %weather]
|
||||
[%home %group-store]
|
||||
[%home %group-hook]
|
||||
[%home %permission-store]
|
||||
[%home %permission-group-hook]
|
||||
==
|
||||
:~ [%home %lens]
|
||||
[%home %acme]
|
||||
[%home %dns]
|
||||
[%home %dojo]
|
||||
[%home %hall]
|
||||
[%home %talk]
|
||||
[%home %modulo]
|
||||
[%home %launch]
|
||||
[%home %chat]
|
||||
[%home %publish]
|
||||
[%home %clock]
|
||||
[%home %weather]
|
||||
[%home %group-store]
|
||||
[%home %group-hook]
|
||||
[%home %permission-store]
|
||||
[%home %permission-group-hook]
|
||||
[%home %azimuth-tracker]
|
||||
=- (turn - |=(a=term home+a))
|
||||
^- (list term)
|
||||
?: lit
|
||||
:~ %dojo
|
||||
%azimuth-tracker
|
||||
==
|
||||
%+ welp
|
||||
?: ?=(%pawn (clan:title our)) ~
|
||||
:~ %acme
|
||||
%dns
|
||||
%azimuth-tracker
|
||||
==
|
||||
:~ %lens
|
||||
%dojo
|
||||
%modulo
|
||||
%launch
|
||||
%publish
|
||||
%clock
|
||||
%weather
|
||||
%group-store
|
||||
%group-hook
|
||||
%permission-store
|
||||
%permission-hook
|
||||
%permission-group-hook
|
||||
%chat-store
|
||||
%chat-hook
|
||||
%chat-view
|
||||
%chat-cli
|
||||
==
|
||||
::
|
||||
++ deft-fish :: default connects
|
||||
|= our/ship
|
||||
%- ~(gas in *(set gill:gall))
|
||||
^- (list gill:gall)
|
||||
[[our %talk] [our %dojo] ~]
|
||||
[[our %chat-cli] [our %dojo] ~]
|
||||
::
|
||||
++ make :: initial part
|
||||
|= our/ship
|
||||
@ -283,9 +274,14 @@
|
||||
::
|
||||
++ se-adit :: update servers
|
||||
^+ .
|
||||
:: ensure dojo connects after talk
|
||||
=* dojo-on-top aor
|
||||
%+ roll (sort ~(tap in ray) dojo-on-top)
|
||||
%+ roll
|
||||
:: ensure dojo is first in the list,
|
||||
:: guaranteeing its display on-boot.
|
||||
::
|
||||
%+ sort ~(tap in ray)
|
||||
|= [a=well:gall b=well:gall]
|
||||
?: |(=(%dojo q.a) =(%dojo q.b)) =(%dojo q.a)
|
||||
(aor a b)
|
||||
=< .(con +>)
|
||||
|: $:{wel/well:gall con/_..se-adit} ^+ con
|
||||
=. +>.$ con
|
||||
|
@ -36,6 +36,12 @@
|
||||
:: hash again to prevent length extension attacks
|
||||
(sha-256l:sha 32 -)
|
||||
::
|
||||
++ ownership-wallet-from-ticket
|
||||
|= [who=ship ticket=byts pass=(unit @t)]
|
||||
^- node
|
||||
=+ master-seed=(argon2u who ticket)
|
||||
(child-node-from-seed master-seed "ownership" pass)
|
||||
::
|
||||
++ full-wallet-from-ticket
|
||||
:: who: username
|
||||
:: ticket: password
|
||||
|
@ -1,58 +1,11 @@
|
||||
::
|
||||
::
|
||||
/- chat, hall
|
||||
/+ hall-json
|
||||
::
|
||||
|_ act=action:chat
|
||||
++ grow
|
||||
|%
|
||||
++ tank !!
|
||||
--
|
||||
::
|
||||
/+ *chat-json
|
||||
=, dejs:format
|
||||
|_ act=chat-action
|
||||
++ grab
|
||||
|%
|
||||
++ noun action:chat
|
||||
++ json
|
||||
++ noun chat-action
|
||||
++ json
|
||||
|= jon=^json
|
||||
=< (parse-chat-action jon)
|
||||
|%
|
||||
::
|
||||
++ hall-action
|
||||
=, dejs:hall-json
|
||||
=, dejs-soft:format
|
||||
|= a=^json
|
||||
^- action:hall
|
||||
=- (need ((of -) a))
|
||||
:~ create+(ot nom+so des+so sec+secu ~)
|
||||
design+(ot nom+so cof+conf ~)
|
||||
delete+(ot nom+so why+(mu so) ~)
|
||||
depict+(ot nom+so des+so ~)
|
||||
filter+(ot nom+so fit+filt ~)
|
||||
permit+(ot nom+so inv+bo sis+(as (su fed:ag)) ~)
|
||||
source+(ot nom+so sub+bo srs+(as sorc) ~)
|
||||
read+(ot nom+so red+ni ~)
|
||||
usage+(ot nom+so add+bo tas+(as so) ~)
|
||||
newdm+(ot sis+(as (su fed:ag)) ~)
|
||||
::
|
||||
convey+(ar thot)
|
||||
phrase+(ot aud+audi ses+(ar spec:dejs:hall-json) ~)
|
||||
::
|
||||
notify+(ot aud+audi pes+(mu pres) ~)
|
||||
naming+(ot aud+audi man+huma ~)
|
||||
::
|
||||
glyph+(ot gyf+so aud+audi bin+bo ~)
|
||||
nick+(ot who+(su fed:ag) nic+so ~)
|
||||
::
|
||||
public+(ot add+bo cir+circ ~)
|
||||
==
|
||||
::
|
||||
++ parse-chat-action
|
||||
=, dejs:format
|
||||
%- of
|
||||
:~
|
||||
[%actions (ot lis+(ar hall-action) ~)]
|
||||
==
|
||||
::
|
||||
--
|
||||
(json-to-action jon)
|
||||
--
|
||||
--
|
||||
|
@ -1,48 +1,14 @@
|
||||
/+ *chat-json
|
||||
|_ cfg=config
|
||||
::
|
||||
::
|
||||
/? 309
|
||||
::
|
||||
/- chat, hall
|
||||
/+ hall-json
|
||||
::
|
||||
|_ str=streams:chat
|
||||
++ grow
|
||||
|%
|
||||
++ json
|
||||
=, enjs:format
|
||||
^- ^json
|
||||
%+ frond %chat
|
||||
%- pairs
|
||||
:~
|
||||
::
|
||||
[%inbox (conf:enjs:hall-json inbox.str)]
|
||||
::
|
||||
:- %configs
|
||||
%- pairs
|
||||
%+ turn ~(tap by configs.str)
|
||||
|= [cir=circle:hall con=(unit config:hall)]
|
||||
^- [@t ^json]
|
||||
:- (crip (circ:en-tape:hall-json cir))
|
||||
?~(con ~ (conf:enjs:hall-json u.con))
|
||||
::
|
||||
:- %circles :- %a
|
||||
%+ turn ~(tap in circles.str)
|
||||
|= nom=name:hall
|
||||
[%s nom]
|
||||
::
|
||||
:- %peers
|
||||
%- pairs
|
||||
%+ turn ~(tap by peers.str)
|
||||
|= [cir=circle:hall per=(set @p)]
|
||||
^- [@t ^json]
|
||||
:- (crip (circ:en-tape:hall-json cir))
|
||||
[%a (turn ~(tap in per) ship)]
|
||||
::
|
||||
==
|
||||
++ json (conf cfg)
|
||||
--
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun streams:chat
|
||||
++ noun config
|
||||
--
|
||||
::
|
||||
--
|
||||
|
14
pkg/arvo/mar/chat/configs.hoon
Normal file
14
pkg/arvo/mar/chat/configs.hoon
Normal file
@ -0,0 +1,14 @@
|
||||
/+ *chat-json
|
||||
|_ cfg=(map path config)
|
||||
::
|
||||
++ grow
|
||||
|%
|
||||
++ json (configs-to-json cfg)
|
||||
--
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun chat-configs
|
||||
--
|
||||
::
|
||||
--
|
38
pkg/arvo/mar/chat/hook-action.hoon
Normal file
38
pkg/arvo/mar/chat/hook-action.hoon
Normal file
@ -0,0 +1,38 @@
|
||||
/- *chat-hook
|
||||
=, dejs:format
|
||||
|_ act=chat-hook-action
|
||||
++ grab
|
||||
|%
|
||||
++ noun chat-hook-action
|
||||
++ json
|
||||
|= jon=^json
|
||||
=< (parse-chat-hook-action jon)
|
||||
|%
|
||||
++ parse-chat-hook-action
|
||||
%- of
|
||||
:~
|
||||
[%add-owned add-owned]
|
||||
[%add-synced add-synced]
|
||||
[%remove pa]
|
||||
==
|
||||
::
|
||||
++ add-owned
|
||||
%- ot
|
||||
:~ [%path pa]
|
||||
[%security sec]
|
||||
==
|
||||
::
|
||||
++ add-synced
|
||||
%- ot
|
||||
:~ [%ship (su ;~(pfix sig fed:ag))]
|
||||
[%path pa]
|
||||
==
|
||||
::
|
||||
++ sec
|
||||
^- $-(^json chat-security)
|
||||
(su (perk %channel %village %journal %mailbox ~))
|
||||
::
|
||||
--
|
||||
--
|
||||
--
|
||||
|
14
pkg/arvo/mar/chat/initial.hoon
Normal file
14
pkg/arvo/mar/chat/initial.hoon
Normal file
@ -0,0 +1,14 @@
|
||||
/+ *chat-json
|
||||
|_ box=inbox
|
||||
::
|
||||
++ grow
|
||||
|%
|
||||
++ json (inbox-to-json box)
|
||||
--
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun inbox
|
||||
--
|
||||
::
|
||||
--
|
@ -1,96 +1,13 @@
|
||||
::
|
||||
::
|
||||
/? 309
|
||||
::
|
||||
/- chat, hall
|
||||
/+ hall-json
|
||||
::
|
||||
|_ upd=update:chat
|
||||
/+ *chat-json
|
||||
|_ upd=chat-update
|
||||
++ grow
|
||||
|%
|
||||
++ json
|
||||
=, enjs:format
|
||||
^- ^json
|
||||
%+ frond %update
|
||||
%- pairs
|
||||
:~
|
||||
::
|
||||
:: %inbox
|
||||
?: =(%inbox -.upd)
|
||||
?> ?=(%inbox -.upd)
|
||||
[%inbox (conf:enjs:hall-json con.upd)]
|
||||
::
|
||||
:: %message
|
||||
?: =(%message -.upd)
|
||||
?> ?=(%message -.upd)
|
||||
:- %message
|
||||
%- pairs
|
||||
:~
|
||||
[%circle (circ:enjs:hall-json cir.upd)]
|
||||
[%envelope (enve:enjs:hall-json env.upd)]
|
||||
==
|
||||
::
|
||||
:: %messages
|
||||
?: =(%messages -.upd)
|
||||
?> ?=(%messages -.upd)
|
||||
:- %messages
|
||||
%- pairs
|
||||
:~
|
||||
[%circle (circ:enjs:hall-json cir.upd)]
|
||||
[%start (numb start.upd)]
|
||||
[%end (numb end.upd)]
|
||||
[%envelopes [%a (turn env.upd enve:enjs:hall-json)]]
|
||||
==
|
||||
::
|
||||
:: %config
|
||||
?: =(%config -.upd)
|
||||
?> ?=(%config -.upd)
|
||||
:- %config
|
||||
%- pairs
|
||||
:~
|
||||
[%circle (circ:enjs:hall-json cir.upd)]
|
||||
[%config (conf:enjs:hall-json con.upd)]
|
||||
==
|
||||
::
|
||||
:: %circles
|
||||
?: =(%circles -.upd)
|
||||
?> ?=(%circles -.upd)
|
||||
:- %circles
|
||||
%- pairs
|
||||
:~
|
||||
:- %circles
|
||||
:- %a
|
||||
%+ turn ~(tap in cir.upd)
|
||||
|= nom=name:hall
|
||||
[%s nom]
|
||||
==
|
||||
::
|
||||
:: %peers
|
||||
?: =(%peers -.upd)
|
||||
?> ?=(%peers -.upd)
|
||||
:- %peers
|
||||
%- pairs
|
||||
:~
|
||||
[%circle (circ:enjs:hall-json cir.upd)]
|
||||
[%peers [%a (turn ~(tap in per.upd) ship:enjs:format)]]
|
||||
==
|
||||
::
|
||||
:: %delete
|
||||
?: =(%delete -.upd)
|
||||
?> ?=(%delete -.upd)
|
||||
:- %delete
|
||||
%- pairs
|
||||
:~
|
||||
[%circle (circ:enjs:hall-json cir.upd)]
|
||||
==
|
||||
::
|
||||
:: %noop
|
||||
[*@t *^json]
|
||||
==
|
||||
++ json (update-to-json upd)
|
||||
--
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun update:chat
|
||||
++ noun chat-update
|
||||
--
|
||||
::
|
||||
--
|
||||
|
11
pkg/arvo/mar/chat/view-action.hoon
Normal file
11
pkg/arvo/mar/chat/view-action.hoon
Normal file
@ -0,0 +1,11 @@
|
||||
/+ *chat-json
|
||||
=, dejs:format
|
||||
|_ act=chat-action
|
||||
++ grab
|
||||
|%
|
||||
++ noun chat-view-action
|
||||
++ json
|
||||
|= jon=^json
|
||||
(json-to-view-action jon)
|
||||
--
|
||||
--
|
7
pkg/arvo/mar/permission/hook-action.hoon
Normal file
7
pkg/arvo/mar/permission/hook-action.hoon
Normal file
@ -0,0 +1,7 @@
|
||||
/- *permission-hook
|
||||
|_ act=permission-hook-action
|
||||
++ grab
|
||||
|%
|
||||
++ noun permission-hook-action
|
||||
--
|
||||
--
|
23
pkg/arvo/sur/chat-hook.hoon
Normal file
23
pkg/arvo/sur/chat-hook.hoon
Normal file
@ -0,0 +1,23 @@
|
||||
|%
|
||||
+$ chat-security
|
||||
$? $channel :: black r, black w
|
||||
$village :: white r, white w
|
||||
$journal :: black r, white w
|
||||
$mailbox :: white r, black w
|
||||
==
|
||||
::
|
||||
+$ chat-hook-action
|
||||
$% :: %add-owned: make a chatroom accessible to foreign ships
|
||||
:: specified by the chat-security model
|
||||
::
|
||||
[%add-owned =path security=chat-security]
|
||||
:: %add-synced: mirror a foreign chatroom to our chat-store
|
||||
::
|
||||
[%add-synced =ship =path]
|
||||
:: %remove: stop mirroring a foreign chatroom or allowing a local
|
||||
:: chatroom to be mirrored
|
||||
::
|
||||
[%remove =path]
|
||||
==
|
||||
--
|
||||
|
45
pkg/arvo/sur/chat-store.hoon
Normal file
45
pkg/arvo/sur/chat-store.hoon
Normal file
@ -0,0 +1,45 @@
|
||||
|%
|
||||
+$ serial @uvH
|
||||
::
|
||||
+$ letter
|
||||
$% [%text text=cord]
|
||||
[%url url=cord]
|
||||
[%code expression=cord output=(list tank)]
|
||||
[%me narrative=cord]
|
||||
==
|
||||
::
|
||||
+$ envelope
|
||||
$: uid=serial
|
||||
number=@
|
||||
author=ship
|
||||
when=time
|
||||
=letter
|
||||
==
|
||||
::
|
||||
+$ config
|
||||
$: length=@
|
||||
read=@
|
||||
==
|
||||
::
|
||||
+$ mailbox
|
||||
$: =config
|
||||
envelopes=(list envelope)
|
||||
==
|
||||
::
|
||||
+$ inbox (map path mailbox)
|
||||
::
|
||||
+$ chat-configs (map path config)
|
||||
::
|
||||
+$ chat-action
|
||||
$% [%create =ship =path] :: %create: create a mailbox at ~ship/path
|
||||
[%delete =path] :: %delete: delete a mailbox at path
|
||||
[%message =path =envelope] :: %message: append a message to mailbox
|
||||
[%read =path] :: %read: set mailbox to read
|
||||
==
|
||||
::
|
||||
+$ chat-update
|
||||
$% [%keys keys=(set path)]
|
||||
[%config =path =config]
|
||||
chat-action
|
||||
==
|
||||
--
|
14
pkg/arvo/sur/chat-view.hoon
Normal file
14
pkg/arvo/sur/chat-view.hoon
Normal file
@ -0,0 +1,14 @@
|
||||
|%
|
||||
+$ chat-security
|
||||
$? $channel :: black r, black w
|
||||
$village :: white r, white w
|
||||
$journal :: black r, white w
|
||||
$mailbox :: white r, black w
|
||||
==
|
||||
::
|
||||
+$ chat-view-action
|
||||
$% [%create =path security=chat-security read=(set ship) write=(set ship)]
|
||||
[%delete =path]
|
||||
[%join =ship =path]
|
||||
==
|
||||
--
|
15
pkg/arvo/sur/permission-hook.hoon
Normal file
15
pkg/arvo/sur/permission-hook.hoon
Normal file
@ -0,0 +1,15 @@
|
||||
|%
|
||||
+$ permission-hook-action
|
||||
$% :: %add-owned: make a permission set accessible to foreign ships
|
||||
:: who are allowed by the permission set at the access path.
|
||||
::
|
||||
[%add-owned owned=path access=path]
|
||||
:: %add-synced: mirror a foreign permission set to our permission-store
|
||||
::
|
||||
[%add-synced =ship =path]
|
||||
:: %remove: stop mirroring a foreign permission set or allowing a local
|
||||
:: permission set to be mirrored
|
||||
::
|
||||
[%remove =path]
|
||||
==
|
||||
--
|
@ -1197,10 +1197,10 @@
|
||||
?: (gor b n.a)
|
||||
=+ c=$(a l.a)
|
||||
?> ?=(^ c)
|
||||
[n.c l.c [n.a r.c r.a]]
|
||||
c(r a(l r.c))
|
||||
=+ c=$(a r.a)
|
||||
?> ?=(^ c)
|
||||
[n.c [n.a l.a l.c] r.c]
|
||||
c(l a(r l.c))
|
||||
::
|
||||
++ del :: b without any a
|
||||
~/ %del
|
||||
@ -1210,14 +1210,14 @@
|
||||
~
|
||||
?. =(b n.a)
|
||||
?: (gor b n.a)
|
||||
[n.a $(a l.a) r.a]
|
||||
[n.a l.a $(a r.a)]
|
||||
a(l $(a l.a))
|
||||
a(r $(a r.a))
|
||||
|- ^- {$?(~ _a)}
|
||||
?~ l.a r.a
|
||||
?~ r.a l.a
|
||||
?: (mor n.l.a n.r.a)
|
||||
[n.l.a l.l.a $(l.a r.l.a)]
|
||||
[n.r.a $(r.a l.r.a) r.r.a]
|
||||
l.a(r $(l.a r.l.a))
|
||||
r.a(l $(r.a l.r.a))
|
||||
::
|
||||
++ dif :: difference
|
||||
~/ %dif
|
||||
@ -1235,8 +1235,8 @@
|
||||
?~ d e
|
||||
?~ e d
|
||||
?: (mor n.d n.e)
|
||||
[n.d l.d $(d r.d)]
|
||||
[n.e $(e l.e) r.e]
|
||||
d(r $(d r.d))
|
||||
e(l $(e l.e))
|
||||
--
|
||||
::
|
||||
++ dig :: axis of a in b
|
||||
@ -1298,10 +1298,10 @@
|
||||
?. (mor n.a n.b)
|
||||
$(a b, b a)
|
||||
?: =(n.b n.a)
|
||||
[n.a $(a l.a, b l.b) $(a r.a, b r.b)]
|
||||
a(l $(a l.a, b l.b), r $(a r.a, b r.b))
|
||||
?: (gor n.b n.a)
|
||||
%- uni(a $(a l.a, b [n.b l.b ~])) $(b r.b)
|
||||
%- uni(a $(a r.a, b [n.b ~ r.b])) $(b l.b)
|
||||
%- uni(a $(a l.a, r.b ~)) $(b r.b)
|
||||
%- uni(a $(a r.a, l.b ~)) $(b l.b)
|
||||
--
|
||||
::
|
||||
++ put :: puts b in a, sorted
|
||||
@ -1316,13 +1316,13 @@
|
||||
=+ c=$(a l.a)
|
||||
?> ?=(^ c)
|
||||
?: (mor n.a n.c)
|
||||
[n.a c r.a]
|
||||
[n.c l.c [n.a r.c r.a]]
|
||||
a(l c)
|
||||
c(r a(l r.c))
|
||||
=+ c=$(a r.a)
|
||||
?> ?=(^ c)
|
||||
?: (mor n.a n.c)
|
||||
[n.a l.a c]
|
||||
[n.c [n.a l.a l.c] r.c]
|
||||
a(r c)
|
||||
c(r a(r l.c))
|
||||
::
|
||||
++ rep :: replace by product
|
||||
|* b/_=>(~ |=({* *} +<+))
|
||||
@ -1359,17 +1359,15 @@
|
||||
a
|
||||
?~ a
|
||||
b
|
||||
?: =(n.b n.a)
|
||||
b(l $(a l.a, b l.b), r $(a r.a, b r.b))
|
||||
?: (mor n.a n.b)
|
||||
?: =(n.b n.a)
|
||||
[n.b $(a l.a, b l.b) $(a r.a, b r.b)]
|
||||
?: (gor n.b n.a)
|
||||
$(a [n.a $(a l.a, b [n.b l.b ~]) r.a], b r.b)
|
||||
$(a [n.a l.a $(a r.a, b [n.b ~ r.b])], b l.b)
|
||||
?: =(n.a n.b)
|
||||
[n.b $(b l.b, a l.a) $(b r.b, a r.a)]
|
||||
$(l.a $(a l.a, r.b ~), b r.b)
|
||||
$(r.a $(a r.a, l.b ~), b l.b)
|
||||
?: (gor n.a n.b)
|
||||
$(b [n.b $(b l.b, a [n.a l.a ~]) r.b], a r.a)
|
||||
$(b [n.b l.b $(b r.b, a [n.a ~ r.a])], a l.a)
|
||||
$(l.b $(b l.b, r.a ~), a r.a)
|
||||
$(r.b $(b r.b, l.a ~), a l.a)
|
||||
--
|
||||
::
|
||||
++ wyt :: size of set
|
||||
@ -1414,14 +1412,14 @@
|
||||
?: =(b p.n.a)
|
||||
?: =(c q.n.a)
|
||||
a
|
||||
[[b c] l.a r.a]
|
||||
a(n [b c])
|
||||
?: (gor b p.n.a)
|
||||
=+ d=$(a l.a)
|
||||
?> ?=(^ d)
|
||||
[n.d l.d [n.a r.d r.a]]
|
||||
d(r a(l r.d))
|
||||
=+ d=$(a r.a)
|
||||
?> ?=(^ d)
|
||||
[n.d [n.a l.a l.d] r.d]
|
||||
d(l a(r l.d))
|
||||
::
|
||||
++ del :: delete at key b
|
||||
~/ %del
|
||||
@ -1431,14 +1429,14 @@
|
||||
~
|
||||
?. =(b p.n.a)
|
||||
?: (gor b p.n.a)
|
||||
[n.a $(a l.a) r.a]
|
||||
[n.a l.a $(a r.a)]
|
||||
a(l $(a l.a))
|
||||
a(r $(a r.a))
|
||||
|- ^- {$?(~ _a)}
|
||||
?~ l.a r.a
|
||||
?~ r.a l.a
|
||||
?: (mor p.n.l.a p.n.r.a)
|
||||
[n.l.a l.l.a $(l.a r.l.a)]
|
||||
[n.r.a $(r.a l.r.a) r.r.a]
|
||||
l.a(r $(l.a r.l.a))
|
||||
r.a(l $(r.a l.r.a))
|
||||
::
|
||||
++ dif :: difference
|
||||
~/ %dif
|
||||
@ -1456,8 +1454,8 @@
|
||||
?~ d e
|
||||
?~ e d
|
||||
?: (mor p.n.d p.n.e)
|
||||
[n.d l.d $(d r.d)]
|
||||
[n.e $(e l.e) r.e]
|
||||
d(r $(d r.d))
|
||||
e(l $(e l.e))
|
||||
--
|
||||
::
|
||||
++ dig :: axis of b key
|
||||
@ -1527,15 +1525,15 @@
|
||||
~
|
||||
?: (mor p.n.a p.n.b)
|
||||
?: =(p.n.b p.n.a)
|
||||
[n.b $(a l.a, b l.b) $(a r.a, b r.b)]
|
||||
b(l $(a l.a, b l.b), r $(a r.a, b r.b))
|
||||
?: (gor p.n.b p.n.a)
|
||||
%- uni(a $(a l.a, b [n.b l.b ~])) $(b r.b)
|
||||
%- uni(a $(a r.a, b [n.b ~ r.b])) $(b l.b)
|
||||
%- uni(a $(a l.a, r.b ~)) $(b r.b)
|
||||
%- uni(a $(a r.a, l.b ~)) $(b l.b)
|
||||
?: =(p.n.a p.n.b)
|
||||
[n.b $(b l.b, a l.a) $(b r.b, a r.a)]
|
||||
b(l $(b l.b, a l.a), r $(b r.b, a r.a))
|
||||
?: (gor p.n.a p.n.b)
|
||||
%- uni(a $(b l.b, a [n.a l.a ~])) $(a r.a)
|
||||
%- uni(a $(b r.b, a [n.a ~ r.a])) $(a l.a)
|
||||
%- uni(a $(b l.b, r.a ~)) $(a r.a)
|
||||
%- uni(a $(b r.b, l.a ~)) $(a l.a)
|
||||
--
|
||||
::
|
||||
++ jab
|
||||
@ -1568,18 +1566,18 @@
|
||||
?: =(b p.n.a)
|
||||
?: =(c q.n.a)
|
||||
a
|
||||
[[b c] l.a r.a]
|
||||
a(n [b c])
|
||||
?: (gor b p.n.a)
|
||||
=+ d=$(a l.a)
|
||||
?> ?=(^ d)
|
||||
?: (mor p.n.a p.n.d)
|
||||
[n.a d r.a]
|
||||
[n.d l.d [n.a r.d r.a]]
|
||||
a(l d)
|
||||
d(r a(l r.d))
|
||||
=+ d=$(a r.a)
|
||||
?> ?=(^ d)
|
||||
?: (mor p.n.a p.n.d)
|
||||
[n.a l.a d]
|
||||
[n.d [n.a l.a l.d] r.d]
|
||||
a(r d)
|
||||
d(l a(r l.d))
|
||||
::
|
||||
++ rep :: replace by product
|
||||
|* b/_=>(~ |=({* *} +<+))
|
||||
@ -1595,7 +1593,7 @@
|
||||
=. n.a +.d
|
||||
=+ e=$(a l.a, b -.d)
|
||||
=+ f=$(a r.a, b -.e)
|
||||
[-.f [n.a +.e +.f]]
|
||||
[-.f a(l +.e, r +.f)]
|
||||
::
|
||||
++ run :: apply gate to values
|
||||
|* b/gate
|
||||
@ -1628,17 +1626,15 @@
|
||||
a
|
||||
?~ a
|
||||
b
|
||||
?: =(p.n.b p.n.a)
|
||||
b(l $(a l.a, b l.b), r $(a r.a, b r.b))
|
||||
?: (mor p.n.a p.n.b)
|
||||
?: =(p.n.b p.n.a)
|
||||
[n.b $(a l.a, b l.b) $(a r.a, b r.b)]
|
||||
?: (gor p.n.b p.n.a)
|
||||
$(a [n.a $(a l.a, b [n.b l.b ~]) r.a], b r.b)
|
||||
$(a [n.a l.a $(a r.a, b [n.b ~ r.b])], b l.b)
|
||||
?: =(p.n.a p.n.b)
|
||||
[n.b $(b l.b, a l.a) $(b r.b, a r.a)]
|
||||
$(l.a $(a l.a, r.b ~), b r.b)
|
||||
$(r.a $(a r.a, l.b ~), b l.b)
|
||||
?: (gor p.n.a p.n.b)
|
||||
$(b [n.b $(b l.b, a [n.a l.a ~]) r.b], a r.a)
|
||||
$(b [n.b l.b $(b r.b, a [n.a ~ r.a])], a l.a)
|
||||
$(l.b $(b l.b, r.a ~), a r.a)
|
||||
$(r.b $(b r.b, l.a ~), a l.a)
|
||||
--
|
||||
::
|
||||
++ uno :: general union
|
||||
@ -1651,19 +1647,17 @@
|
||||
a
|
||||
?~ a
|
||||
b
|
||||
?: (mor p.n.a p.n.b)
|
||||
?: =(p.n.b p.n.a)
|
||||
[n.b $(a l.a, b l.b) $(a r.a, b r.b)]
|
||||
?: (gor p.n.b p.n.a)
|
||||
$(a [n.a $(a l.a, b [n.b l.b ~]) r.a], b r.b)
|
||||
$(a [n.a l.a $(a r.a, b [n.b ~ r.b])], b l.b)
|
||||
?: =(p.n.a p.n.b)
|
||||
?: =(p.n.b p.n.a)
|
||||
:+ [p.n.a (meg p.n.a q.n.a q.n.b)]
|
||||
$(b l.b, a l.a)
|
||||
$(b r.b, a r.a)
|
||||
?: (mor p.n.a p.n.b)
|
||||
?: (gor p.n.b p.n.a)
|
||||
$(l.a $(a l.a, r.b ~), b r.b)
|
||||
$(r.a $(a r.a, l.b ~), b l.b)
|
||||
?: (gor p.n.a p.n.b)
|
||||
$(b [n.b $(b l.b, a [n.a l.a ~]) r.b], a r.a)
|
||||
$(b [n.b l.b $(b r.b, a [n.a ~ r.a])], a l.a)
|
||||
$(l.b $(b l.b, r.a ~), a r.a)
|
||||
$(r.b $(b r.b, l.a ~), a l.a)
|
||||
--
|
||||
::
|
||||
::
|
||||
@ -1671,7 +1665,7 @@
|
||||
|* b/$-({* *} *)
|
||||
|-
|
||||
?~ a ~
|
||||
[n=[p=p.n.a q=(b p.n.a q.n.a)] l=$(a l.a) r=$(a r.a)]
|
||||
a(n n.a(q (b p.n.a q.n.a)), l $(a l.a), r $(a r.a))
|
||||
::
|
||||
++ wyt :: depth of map
|
||||
|- ^- @
|
||||
@ -1750,20 +1744,19 @@
|
||||
=| a/(tree) :: (qeu)
|
||||
|@
|
||||
++ apt :: check correctness
|
||||
^- ?
|
||||
?~ a &
|
||||
|- ^- ?
|
||||
?~ l.a &
|
||||
?~ r.a &
|
||||
&((mor n.l.a n.r.a) $(a l.a) $(a r.a))
|
||||
?~ a &
|
||||
?& ?~(l.a & ?&((mor n.a n.l.a) $(a l.a)))
|
||||
?~(r.a & ?&((mor n.a n.r.a) $(a r.a)))
|
||||
==
|
||||
::
|
||||
++ bal
|
||||
|- ^+ a
|
||||
?~ a ~
|
||||
?. |(?=(~ l.a) (mor n.a n.l.a))
|
||||
$(a [n.l.a l.l.a $(a [n.a r.l.a r.a])])
|
||||
$(a l.a(r $(a a(l r.l.a))))
|
||||
?. |(?=(~ r.a) (mor n.a n.r.a))
|
||||
$(a [n.r.a $(a [n.a l.a l.r.a]) r.r.a])
|
||||
$(a r.a(l $(a a(r l.r.a))))
|
||||
a
|
||||
::
|
||||
++ dep :: max depth of queue
|
||||
@ -1785,30 +1778,30 @@
|
||||
=+ b=$(a r.a)
|
||||
:- p.b
|
||||
?: |(?=(~ q.b) (mor n.a n.q.b))
|
||||
[n.a l.a q.b]
|
||||
[n.q.b [n.a l.a l.q.b] r.q.b]
|
||||
a(r q.b)
|
||||
a(n n.q.b, l a(r l.q.b), r r.q.b)
|
||||
::
|
||||
++ nip :: remove root
|
||||
++ nip :: removes root
|
||||
|- ^+ a
|
||||
?~ a ~
|
||||
?~ l.a r.a
|
||||
?~ r.a l.a
|
||||
?: (mor n.l.a n.r.a)
|
||||
[n.l.a l.l.a $(l.a r.l.a)]
|
||||
[n.r.a $(r.a l.r.a) r.r.a]
|
||||
l.a(r $(l.a r.l.a))
|
||||
r.a(l $(r.a l.r.a))
|
||||
::
|
||||
++ nap :: removes head
|
||||
++ nap :: removes root
|
||||
?> ?=(^ a)
|
||||
?: =(~ l.a) r.a
|
||||
=+ b=get(a l.a)
|
||||
bal(a ^+(a [p.b q.b r.a]))
|
||||
bal(n.a p.b, l.a q.b)
|
||||
::
|
||||
++ put :: insert new tail
|
||||
|* b/*
|
||||
|- ^+ a
|
||||
?~ a
|
||||
[b ~ ~]
|
||||
bal(a a(l $(a l.a)))
|
||||
bal(l.a $(a l.a))
|
||||
::
|
||||
++ tap :: adds list to end
|
||||
=+ b=`(list _?>(?=(^ a) n.a))`~
|
||||
|
@ -1385,6 +1385,13 @@
|
||||
[[gad.fox [%give %send p.bon q.bon]] ~]
|
||||
::
|
||||
%pito
|
||||
:: ignore/unset timer if we haven't yet learned a unix duct
|
||||
::
|
||||
:: Only happens during first boot.
|
||||
::
|
||||
?~ gad.fox
|
||||
[~ fox(tim ~)]
|
||||
::
|
||||
:_ fox(tim `p.bon)
|
||||
%- flop
|
||||
^- (list move)
|
||||
|
@ -91,6 +91,7 @@
|
||||
=. movs.drips.state (~(del by movs.drips.state) num)
|
||||
?^ error
|
||||
:: if we errored, drop it
|
||||
%- (slog leaf/"drip failed" u.error)
|
||||
event-core
|
||||
event-core(moves [duct %give %meta drip]~)
|
||||
:: +trim: in response to memory pressue
|
||||
|
@ -83,7 +83,7 @@
|
||||
++ axle
|
||||
$: :: date: date at which http-server's state was updated to this data structure
|
||||
::
|
||||
date=%~2019.1.7
|
||||
date=%~2019.10.6
|
||||
:: server-state: state of inbound requests
|
||||
::
|
||||
=server-state
|
||||
@ -216,8 +216,6 @@
|
||||
:: 'Last-Event-Id: ' header to the server; the server then resends all
|
||||
:: events since then.
|
||||
::
|
||||
:: TODO: Send \n as a heartbeat every 20 seconds.
|
||||
::
|
||||
+$ channel
|
||||
$: :: channel-state: expiration time or the duct currently listening
|
||||
::
|
||||
@ -246,6 +244,9 @@
|
||||
:: can cancel all the subscriptions we've made.
|
||||
::
|
||||
subscriptions=(map wire [ship=@p app=term =path duc=duct])
|
||||
:: heartbeat: sse heartbeat timer
|
||||
::
|
||||
heartbeat=(unit timer)
|
||||
==
|
||||
:: channel-request: an action requested on a channel
|
||||
::
|
||||
@ -1009,7 +1010,7 @@
|
||||
=/ max-age=tape (format-ud-as-integer `@ud`(div (msec:milly expires-in) 1.000))
|
||||
=/ cookie-line
|
||||
%- crip
|
||||
"urbauth={<session>}; Path=/; Max-Age={max-age}"
|
||||
"urbauth-{<our>}={<session>}; Path=/; Max-Age={max-age}"
|
||||
::
|
||||
?~ redirect=(get-header:http 'redirect' u.parsed)
|
||||
%- handle-response
|
||||
@ -1053,7 +1054,7 @@
|
||||
%.n
|
||||
:: is there an urbauth cookie?
|
||||
::
|
||||
?~ urbauth=(get-header:http 'urbauth' u.cookies)
|
||||
?~ urbauth=(get-header:http (crip "urbauth-{<our>}") u.cookies)
|
||||
%.n
|
||||
:: is this formatted like a valid session cookie?
|
||||
::
|
||||
@ -1147,9 +1148,22 @@
|
||||
::
|
||||
~& [%canceling-cancel duct]
|
||||
::
|
||||
=/ maybe-session
|
||||
(~(get by session.channel-state.state) u.maybe-channel-id)
|
||||
?~ maybe-session [~ state]
|
||||
::
|
||||
=/ heartbeat-cancel=(list move)
|
||||
?~ heartbeat.u.maybe-session ~
|
||||
:~ %^ cancel-heartbeat-move
|
||||
u.maybe-channel-id
|
||||
date.u.heartbeat.u.maybe-session
|
||||
duct.u.heartbeat.u.maybe-session
|
||||
==
|
||||
::
|
||||
=/ expiration-time=@da (add now channel-timeout)
|
||||
::
|
||||
:- [(set-timeout-move u.maybe-channel-id expiration-time) moves]
|
||||
:- %+ weld heartbeat-cancel
|
||||
[(set-timeout-move u.maybe-channel-id expiration-time) moves]
|
||||
%_ state
|
||||
session.channel-state
|
||||
%+ ~(jab by session.channel-state.state) u.maybe-channel-id
|
||||
@ -1157,7 +1171,7 @@
|
||||
:: if we are canceling a known channel, it should have a listener
|
||||
::
|
||||
?> ?=([%| *] state.channel)
|
||||
channel(state [%& [expiration-time duct]])
|
||||
channel(state [%& [expiration-time duct]], heartbeat ~)
|
||||
::
|
||||
duct-to-key.channel-state
|
||||
(~(del by duct-to-key.channel-state.state) duct)
|
||||
@ -1182,7 +1196,7 @@
|
||||
%_ ..update-timeout-timer-for
|
||||
session.channel-state.state
|
||||
%+ ~(put by session.channel-state.state) channel-id
|
||||
[[%& expiration-time duct] 0 ~ ~]
|
||||
[[%& expiration-time duct] 0 ~ ~ ~]
|
||||
::
|
||||
moves
|
||||
[(set-timeout-move channel-id expiration-time) moves]
|
||||
@ -1206,6 +1220,18 @@
|
||||
==
|
||||
==
|
||||
::
|
||||
++ set-heartbeat-move
|
||||
|= [channel-id=@t heartbeat-time=@da]
|
||||
^- move
|
||||
:^ duct %pass /channel/heartbeat/[channel-id]
|
||||
[%b %wait heartbeat-time]
|
||||
::
|
||||
++ cancel-heartbeat-move
|
||||
|= [channel-id=@t heartbeat-time=@da =^duct]
|
||||
^- move
|
||||
:^ duct %pass /channel/heartbeat/[channel-id]
|
||||
[%b %rest heartbeat-time]
|
||||
::
|
||||
++ set-timeout-move
|
||||
|= [channel-id=@t expiration-time=@da]
|
||||
^- move
|
||||
@ -1278,14 +1304,19 @@
|
||||
::
|
||||
=. duct-to-key.channel-state.state
|
||||
(~(put by duct-to-key.channel-state.state) duct channel-id)
|
||||
:: clear the event queue and record the duct for future output
|
||||
:: initialize sse heartbeat
|
||||
::
|
||||
=/ heartbeat-time=@da (add now ~s20)
|
||||
=/ heartbeat (set-heartbeat-move channel-id heartbeat-time)
|
||||
:: clear the event queue, record the duct for future output and
|
||||
:: record heartbeat-time for possible future cancel
|
||||
::
|
||||
=. session.channel-state.state
|
||||
%+ ~(jab by session.channel-state.state) channel-id
|
||||
|= =channel
|
||||
channel(events ~, state [%| duct])
|
||||
channel(events ~, state [%| duct], heartbeat (some [heartbeat-time duct]))
|
||||
::
|
||||
[(weld http-moves moves) state]
|
||||
[[heartbeat (weld http-moves moves)] state]
|
||||
:: +acknowledge-events: removes events before :last-event-id on :channel-id
|
||||
::
|
||||
++ acknowledge-events
|
||||
@ -1464,6 +1495,14 @@
|
||||
=. duct-to-key.channel-state.state
|
||||
(~(del by duct-to-key.channel-state.state) p.state.session)
|
||||
::
|
||||
?~ heartbeat.session $(requests t.requests)
|
||||
=. gall-moves
|
||||
%+ snoc gall-moves
|
||||
%^ cancel-heartbeat-move
|
||||
channel-id
|
||||
date.u.heartbeat.session
|
||||
duct.u.heartbeat.session
|
||||
::
|
||||
$(requests t.requests)
|
||||
::
|
||||
==
|
||||
@ -1582,7 +1621,31 @@
|
||||
events (~(put to events.channel) [event-id event-stream-lines])
|
||||
==
|
||||
==
|
||||
:: +on-channel-timeout: we received a wake to clear an old session
|
||||
::
|
||||
++ on-channel-heartbeat
|
||||
|= channel-id=@t
|
||||
^- [(list move) server-state]
|
||||
::
|
||||
?~ connection-state=(~(get by connections.state) duct)
|
||||
[~ state]
|
||||
::
|
||||
=/ res
|
||||
%- handle-response
|
||||
:* %continue
|
||||
data=(some (as-octs:mimes:html '\0a'))
|
||||
complete=%.n
|
||||
==
|
||||
=/ http-moves -.res
|
||||
=/ new-state +.res
|
||||
=/ heartbeat-time=@da (add now ~s20)
|
||||
:_ %_ new-state
|
||||
session.channel-state
|
||||
%+ ~(jab by session.channel-state.state) channel-id
|
||||
|= =channel
|
||||
channel(heartbeat (some [heartbeat-time duct]))
|
||||
==
|
||||
(snoc http-moves (set-heartbeat-move channel-id heartbeat-time))
|
||||
:: +on-channel-timeout: we received a wake to clear an old session
|
||||
::
|
||||
++ on-channel-timeout
|
||||
|= channel-id=@t
|
||||
@ -1598,6 +1661,14 @@
|
||||
session.channel-state
|
||||
(~(del by session.channel-state.state) channel-id)
|
||||
==
|
||||
=/ heartbeat-cancel=(list move)
|
||||
?~ heartbeat.session ~
|
||||
:~ %^ cancel-heartbeat-move
|
||||
channel-id
|
||||
date.u.heartbeat.session
|
||||
duct.u.heartbeat.session
|
||||
==
|
||||
%+ weld heartbeat-cancel
|
||||
:: produce a list of moves which cancels every gall subscription
|
||||
::
|
||||
%+ turn ~(tap by subscriptions.session)
|
||||
@ -2158,6 +2229,13 @@
|
||||
=^ moves server-state.ax
|
||||
(on-channel-timeout i.t.t.wire)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
%heartbeat
|
||||
=/ on-channel-heartbeat
|
||||
on-channel-heartbeat:by-channel:(per-server-event event-args)
|
||||
=^ moves server-state.ax
|
||||
(on-channel-heartbeat i.t.t.wire)
|
||||
[moves http-server-gate]
|
||||
::
|
||||
?(%poke %subscription)
|
||||
?> ?=([%g %unto *] sign)
|
||||
@ -2187,11 +2265,45 @@
|
||||
:: +load: migrate old state to new state (called on vane reload)
|
||||
::
|
||||
++ load
|
||||
|= old=axle
|
||||
=> |%
|
||||
+$ channel-old
|
||||
$: state=(each timer duct)
|
||||
next-id=@ud
|
||||
events=(qeu [id=@ud lines=wall])
|
||||
subscriptions=(map wire [ship=@p app=term =path duc=duct])
|
||||
==
|
||||
+$ channel-state-old
|
||||
$: session=(map @t channel-old)
|
||||
duct-to-key=(map duct @t)
|
||||
==
|
||||
++ axle-old
|
||||
%+ cork
|
||||
axle
|
||||
|= =axle
|
||||
axle(date %~2019.1.7, channel-state.server-state (channel-state-old))
|
||||
--
|
||||
|= old=$%(axle axle-old)
|
||||
^+ ..^$
|
||||
::
|
||||
~! %loading
|
||||
..^$(ax old)
|
||||
?- -.old
|
||||
%~2019.1.7
|
||||
=/ add-heartbeat
|
||||
%- ~(run by session.channel-state.server-state.old)
|
||||
|= [c=channel-old]
|
||||
^- channel
|
||||
[state.c next-id.c events.c subscriptions.c ~]
|
||||
::
|
||||
=/ new
|
||||
%= old
|
||||
date %~2019.10.6
|
||||
session.channel-state.server-state add-heartbeat
|
||||
==
|
||||
$(old new)
|
||||
::
|
||||
%~2019.10.6 ..^$(ax old)
|
||||
==
|
||||
|
||||
:: +stay: produce current state
|
||||
::
|
||||
++ stay `axle`ax
|
||||
|
386
pkg/arvo/tests/sys/hoon/differ.hoon
Normal file
386
pkg/arvo/tests/sys/hoon/differ.hoon
Normal file
@ -0,0 +1,386 @@
|
||||
:: Tests for +differ (a suite of Hunt-McIlroy diff and merge algorithms)
|
||||
::
|
||||
/+ *test
|
||||
::
|
||||
=, differ
|
||||
:: Testing arms
|
||||
::
|
||||
|%
|
||||
:: ++berk:differ: invert diff patch
|
||||
::
|
||||
++ test-berk ^- tang
|
||||
:: An inverted diff between %a and %b can be checked
|
||||
:: by patching %b and obtaining %a
|
||||
::
|
||||
;: weld
|
||||
:: (some) test examples adapted from:
|
||||
:: https://github.com/gioele/diff-lcs/blob/master/test/test_diff-lcs.rb
|
||||
::
|
||||
=/ a "abcehjlmnp"
|
||||
=/ b "bcdefjklmrst"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "abcde"
|
||||
=/ b "ae"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "ae"
|
||||
=/ b "abcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "vxae"
|
||||
=/ b "wyabcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "xae"
|
||||
=/ b "abcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "ae"
|
||||
=/ b "xabcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "aev"
|
||||
=/ b "xabcdewx"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-a (lurk b (berk diff-a-b))
|
||||
=/ patch-b (lurk a (berk diff-b-a))
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
:: individuals diffs
|
||||
::
|
||||
=/ a "10qawsedrftg"
|
||||
=/ b "1Aqawsedrftg"
|
||||
=/ diff=(urge:clay cord)
|
||||
:~ :: copies first match
|
||||
::
|
||||
[%.y 1]
|
||||
:: replaces 0 with 'A'
|
||||
::
|
||||
[%.n "0" "A"]
|
||||
:: copies the rest
|
||||
::
|
||||
[%.y 10]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> a
|
||||
!> (lurk b (berk diff))
|
||||
::
|
||||
=/ a "1qawsedrftg10"
|
||||
=/ b "1Aqawsedrftg"
|
||||
=/ diff=(urge:clay cord)
|
||||
:~ :: copies first match
|
||||
::
|
||||
[%.y 1]
|
||||
:: inserts 'A'
|
||||
::
|
||||
[%.n ~ "A"]
|
||||
:: copies all matches
|
||||
::
|
||||
[%.y 10]
|
||||
:: copies '10'
|
||||
::
|
||||
[%.n (flop "10") ~]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> a
|
||||
!> (lurk b (berk diff))
|
||||
==
|
||||
::
|
||||
:: ++loss:differ: longest subsequence
|
||||
::
|
||||
++ test-loss ^- tang
|
||||
;: weld
|
||||
:: null case
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (loss "abc" "xyz")
|
||||
:: common prefix
|
||||
::
|
||||
%+ expect-eq
|
||||
!> "abc"
|
||||
!> (loss "abcq" "abcxyz")
|
||||
%+ expect-eq
|
||||
!> "qaz"
|
||||
!> (loss "qaz" "qazxyz")
|
||||
:: common suffix
|
||||
::
|
||||
%+ expect-eq
|
||||
!> "wsx"
|
||||
!> (loss "qwsx" "xyzwsx")
|
||||
%+ expect-eq
|
||||
!> "edc"
|
||||
!> (loss "edc" "xyzedc")
|
||||
:: overlap
|
||||
::
|
||||
%+ expect-eq
|
||||
!> "rfv"
|
||||
!> (loss "qrfvp" "xyzrfvdef")
|
||||
%+ expect-eq
|
||||
!> "tgb"
|
||||
!> (loss "qwertytgb" "tgbasdfgh")
|
||||
:: Non contiguous
|
||||
::
|
||||
%+ expect-eq
|
||||
:: Example from wikipedia:
|
||||
:: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
|
||||
::
|
||||
!> "MJAU"
|
||||
!> (loss "XMJYAUZ" "MZJAWXU")
|
||||
%+ expect-eq
|
||||
!> "qawsxcf"
|
||||
!> (loss "qazwsxedcrfvtb" "qqqawsxcf")
|
||||
==
|
||||
::
|
||||
:: ++lurk:differ: apply list patch
|
||||
::
|
||||
++ test-lurk ^- tang
|
||||
;: weld
|
||||
:: (some) test examples adapted from:
|
||||
:: https://github.com/gioele/diff-lcs/blob/master/test/test_diff-lcs.rb
|
||||
::
|
||||
=/ a "abcehjlmnp"
|
||||
=/ b "bcdefjklmrst"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "abcde"
|
||||
=/ b "ae"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "ae"
|
||||
=/ b "abcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "vxae"
|
||||
=/ b "wyabcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "xae"
|
||||
=/ b "abcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "ae"
|
||||
=/ b "xabcde"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
=/ a "aev"
|
||||
=/ b "xabcdewx"
|
||||
=/ diff-a-b (lusk a b (loss a b))
|
||||
=/ diff-b-a (lusk b a (loss b a))
|
||||
=/ patch-b (lurk a diff-a-b)
|
||||
=/ patch-a (lurk b diff-b-a)
|
||||
%+ expect-eq
|
||||
!> a^b
|
||||
!> patch-a^patch-b
|
||||
::
|
||||
:: individuals diffs
|
||||
::
|
||||
=/ a "10qawsedrftg"
|
||||
=/ b "1Aqawsedrftg"
|
||||
=/ diff=(urge:clay cord)
|
||||
:~ :: copies first match
|
||||
::
|
||||
[%.y 1]
|
||||
:: replaces 0 with 'A'
|
||||
::
|
||||
[%.n "0" "A"]
|
||||
:: copies the rest
|
||||
::
|
||||
[%.y 10]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> b
|
||||
!> (lurk a diff)
|
||||
::
|
||||
=/ a "1qawsedrftg10"
|
||||
=/ b "1Aqawsedrftg"
|
||||
=/ diff=(urge:clay cord)
|
||||
:~ :: copies first match
|
||||
::
|
||||
[%.y 1]
|
||||
:: inserts 'A'
|
||||
::
|
||||
[%.n ~ "A"]
|
||||
:: copies all matches
|
||||
::
|
||||
[%.y 10]
|
||||
:: copies '10'
|
||||
::
|
||||
[%.n (flop "10") ~]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> b
|
||||
!> (lurk a diff)
|
||||
==
|
||||
:: ++lusk:differ: lcs to list patch
|
||||
::
|
||||
++ test-lusk ^- tang
|
||||
;: weld
|
||||
:: (some) test examples adapted from:
|
||||
:: https://github.com/gioele/diff-lcs/blob/master/test/test_diff-lcs.rb
|
||||
::
|
||||
=/ a "abcehjlmnp"
|
||||
=/ b "bcdefjklmrst"
|
||||
=/ diff
|
||||
:~ [%.n ~['a'] ~]
|
||||
[%.y 2]
|
||||
[%.n ~ ~['d']]
|
||||
[%.y 1]
|
||||
[%.n ~['h'] ~['f']]
|
||||
[%.y 1]
|
||||
[%.n ~ ~['k']]
|
||||
[%.y 2]
|
||||
[%.n (flop "np") (flop "rst")]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
::
|
||||
=/ a "abcde"
|
||||
=/ b "ae"
|
||||
=/ diff
|
||||
:~ [%.y 1]
|
||||
[%.n (flop "bcd") ~]
|
||||
[%.y 1]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
::
|
||||
=/ a "ae"
|
||||
=/ b "abcde"
|
||||
=/ diff
|
||||
:~ [%.y 1]
|
||||
[%.n ~ (flop "bcd")]
|
||||
[%.y 1]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
::
|
||||
=/ a "vxae"
|
||||
=/ b "wyabcde"
|
||||
=/ diff
|
||||
:~ [%.n (flop "vx") (flop "wy")]
|
||||
[%.y 1]
|
||||
[%.n ~ (flop "bcd")]
|
||||
[%.y 1]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
::
|
||||
=/ a "xae"
|
||||
=/ b "abcde"
|
||||
=/ diff
|
||||
:~ [%.n "x" ~]
|
||||
[%.y 1]
|
||||
[%.n ~ (flop "bcd")]
|
||||
[%.y 1]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
::
|
||||
=/ a "ae"
|
||||
=/ b "xabcde"
|
||||
=/ diff
|
||||
:~ [%.n ~ "x"]
|
||||
[%.y 1]
|
||||
[%.n ~ (flop "bcd")]
|
||||
[%.y 1]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
::
|
||||
=/ a "aev"
|
||||
=/ b "xabcdewx"
|
||||
=/ diff
|
||||
:~ [%.n ~ "x"]
|
||||
[%.y 1]
|
||||
[%.n ~ (flop "bcd")]
|
||||
[%.y 1]
|
||||
[%.n "v" (flop "wx")]
|
||||
==
|
||||
%+ expect-eq
|
||||
!> diff
|
||||
!> (lusk a b (loss a b))
|
||||
==
|
||||
--
|
747
pkg/arvo/tests/sys/hoon/map.hoon
Normal file
747
pkg/arvo/tests/sys/hoon/map.hoon
Normal file
@ -0,0 +1,747 @@
|
||||
:: Tests for +by (map logic)
|
||||
::
|
||||
/+ *test
|
||||
::
|
||||
=> :: Utility core
|
||||
::
|
||||
|%
|
||||
++ map-of-doubles
|
||||
|= l=(list @)
|
||||
^- (map @ @)
|
||||
%- my
|
||||
^- (list (pair @ @))
|
||||
%+ turn l
|
||||
|= k=@
|
||||
[k (mul 2 k)]
|
||||
--
|
||||
::
|
||||
=> :: Test Data
|
||||
::
|
||||
|%
|
||||
+| %test-suite
|
||||
++ m-uno (map-of-doubles ~[42])
|
||||
++ m-dos (map-of-doubles ~[6 9])
|
||||
++ m-tre (map-of-doubles ~[1 0 1])
|
||||
++ m-asc (map-of-doubles ~[1 2 3 4 5 6 7])
|
||||
++ m-des (map-of-doubles ~[7 6 5 4 3 2 1])
|
||||
++ m-uns (map-of-doubles ~[1 6 3 5 7 2 4])
|
||||
++ m-dup (map-of-doubles ~[1 1 7 4 6 9 4])
|
||||
++ m-nul *(map @ @)
|
||||
++ m-lis ~[m-nul m-uno m-dos m-tre m-asc m-des m-uns m-dup]
|
||||
--
|
||||
:: Testing arms
|
||||
::
|
||||
|%
|
||||
:: Test logical AND
|
||||
::
|
||||
++ test-map-all ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(all by m-nul) |=(* &))
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(all by m-nul) |=(* |))
|
||||
:: Checks one element fails
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(all by m-uno) |=(e=@ =(e 43)))
|
||||
:: Checks >1 element fails
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(all by m-dos) |=(e=@ (lth e 4)))
|
||||
:: Checks all elements pass
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(all by m-des) |=(e=@ (lth e 80)))
|
||||
==
|
||||
::
|
||||
:: Test logical OR
|
||||
::
|
||||
++ test-map-any ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any by m-nul) |=(* &))
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any by m-nul) |=(* |))
|
||||
:: Checks one element fails
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any by m-uno) |=(e=@ =(e 43)))
|
||||
:: Checks >1 element fails
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any by m-dos) |=(e=@ (lth e 4)))
|
||||
:: Checks one element passes
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(any by m-des) |=(e=@ =(e 14)))
|
||||
:: Checks all element pass
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(any by m-des) |=(e=@ (lth e 100)))
|
||||
==
|
||||
::
|
||||
:: Test check correctnes (correct horizontal & vertical order)
|
||||
::
|
||||
++ test-map-apt ^- tang
|
||||
:: manually constructed maps with predefined vertical/horizontal
|
||||
:: ordering
|
||||
::
|
||||
:: for the following three keys (1, 2, 3) the vertical priorities are:
|
||||
:: > (mug (mug 1))
|
||||
:: 1.405.103.437
|
||||
:: > (mug (mug 2))
|
||||
:: 1.200.431.393
|
||||
:: > (mug (mug 3))
|
||||
:: 1.576.941.407
|
||||
::
|
||||
:: and the ordering 2 < 1 < 3
|
||||
:: a correctly balanced tree stored as a min-heap
|
||||
:: should have key=2 as the root
|
||||
::
|
||||
:: The horizontal priorities are:
|
||||
:: > (mug 1)
|
||||
:: 1.901.865.568
|
||||
:: > (mug 2)
|
||||
:: 1.904.972.904
|
||||
:: > (mug 3)
|
||||
:: 1.923.673.882
|
||||
::
|
||||
:: and the ordering 1 < 2 < 3.
|
||||
::
|
||||
:: 1 should be in the left brach and 3 in the right one.
|
||||
::
|
||||
=/ balanced-a=(map @ @) [[2 2] [[1 1] ~ ~] [[3 3] ~ ~]]
|
||||
:: doesn't follow vertical ordering
|
||||
::
|
||||
=/ unbalanced-a=(map @ @) [[1 1] [[2 2] ~ ~] [[3 3] ~ ~]]
|
||||
=/ unbalanced-b=(map @ @) [[1 1] ~ [[2 2] ~ ~]]
|
||||
=/ unbalanced-c=(map @ @) [[1 1] [[2 2] ~ ~] ~]
|
||||
:: doesn't follow horizontal ordering
|
||||
::
|
||||
=/ unbalanced-d=(map @ @) [[2 2] [[3 3] ~ ~] [[1 1] ~ ~]]
|
||||
:: doesn't follow horizontal & vertical ordering
|
||||
::
|
||||
=/ unbalanced-e=(map @ @) [[1 1] [[3 3] ~ ~] [[2 2] ~ ~]]
|
||||
;: weld
|
||||
%+ expect-eq
|
||||
!> [%b-a %.y]
|
||||
!> [%b-a ~(apt by balanced-a)]
|
||||
%+ expect-eq
|
||||
!> [%u-a %.n]
|
||||
!> [%u-a ~(apt by unbalanced-a)]
|
||||
%+ expect-eq
|
||||
!> [%u-b %.n]
|
||||
!> [%u-b ~(apt by unbalanced-b)]
|
||||
%+ expect-eq
|
||||
!> [%u-c %.n]
|
||||
!> [%u-c ~(apt by unbalanced-c)]
|
||||
%+ expect-eq
|
||||
!> [%u-d %.n]
|
||||
!> [%u-d ~(apt by unbalanced-d)]
|
||||
%+ expect-eq
|
||||
!> [%u-e %.n]
|
||||
!> [%u-e ~(apt by unbalanced-e)]
|
||||
==
|
||||
::
|
||||
:: Test bifurcation (i.e. splits map a into two, discarding -.a)
|
||||
::
|
||||
++ test-map-bif ^- tang
|
||||
:: The traversal of the +map is done comparing the double +mug
|
||||
:: of the key of the added node and the one from the tree.
|
||||
:: Because of this, the search will stop at different leaves,
|
||||
:: based on the value of the hash, therefore the right and left
|
||||
:: maps that are returned can be different
|
||||
:: (null or a less than the total number of nodes)
|
||||
:: The best way to check is that the sum of the number of nodes
|
||||
:: in both maps are the same as before, and that both returned
|
||||
:: maps are correct
|
||||
::
|
||||
=/ splits-a=[(map) (map)] (~(bif by m-des) [99 99])
|
||||
=/ splits-b=[(map) (map)] (~(bif by m-des) [6 12])
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> [~ ~]
|
||||
!> (~(bif by m-nul) [1 2])
|
||||
:: Checks bifurcating by non-existing element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 7
|
||||
!> (add ~(wyt by -.splits-a) ~(wyt by +.splits-a))
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> &(~(apt by -.splits-a) ~(apt by +.splits-a))
|
||||
:: Checks splitting by existing element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 6
|
||||
!> (add ~(wyt by -.splits-b) ~(wyt by +.splits-b))
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> &(~(apt by -.splits-b) ~(apt by +.splits-b))
|
||||
=/ left (~(get by -.splits-b) [6 12])
|
||||
=/ right (~(get by +.splits-b) [6 12])
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> &(=(left ~) =(right ~))
|
||||
==
|
||||
::
|
||||
:: Test delete at key b
|
||||
::
|
||||
++ test-map-del ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(del by m-nul) 1)
|
||||
:: Checks deleting non-existing element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-des
|
||||
!> (~(del by m-des) 99)
|
||||
:: Checks deleting the only element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(del by m-uno) 42)
|
||||
:: Checks deleting one element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (map-of-doubles (limo ~[6 5 4 3 2 1]))
|
||||
!> (~(del by m-des) 7)
|
||||
==
|
||||
::
|
||||
:: Test difference (removes elements of a present in b)
|
||||
::
|
||||
++ test-map-dif ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dif by ~) ~)
|
||||
%+ expect-eq
|
||||
!> m-dup
|
||||
!> (~(dif by m-dup) m-nul)
|
||||
:: Checks same elements, different ordering
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dif by m-asc) m-des)
|
||||
:: Checks different map length
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[7 14] [1 2] [4 8]])
|
||||
!> (~(dif by m-dup) m-dos)
|
||||
:: Checks no elements in common
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-uno
|
||||
!> (~(dif by m-uno) m-dos)
|
||||
==
|
||||
::
|
||||
:: Test axis of a in b
|
||||
::
|
||||
++ test-map-dig ^- tang
|
||||
=/ custom [[2 4] [[1 2] ~ ~] [[3 6] ~ ~]]
|
||||
=/ custome-vase !>(custom)
|
||||
=/ manual-map=(map @ @) custom
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dig by m-nul) 6)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dig by m-des) 9)
|
||||
:: Checks success via tree addressing. Uses the return axis
|
||||
:: to address the raw noun and check that it gives the corresponding
|
||||
:: value from the key.
|
||||
::
|
||||
%+ expect-eq
|
||||
!> [1 (~(got by manual-map) 1)]
|
||||
!> +:(slot (need (~(dig by manual-map) 1)) custome-vase)
|
||||
%+ expect-eq
|
||||
!> [2 (~(got by manual-map) 2)]
|
||||
!> +:(slot (need (~(dig by manual-map) 2)) custome-vase)
|
||||
%+ expect-eq
|
||||
!> [3 (~(got by manual-map) 3)]
|
||||
!> +:(slot (need (~(dig by manual-map) 3)) custome-vase)
|
||||
==
|
||||
::
|
||||
:: Test concatenate
|
||||
::
|
||||
++ test-map-gas ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-dos
|
||||
!> (~(gas by m-nul) ~[[6 12] [9 18]])
|
||||
:: Checks with > 1 element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (map-of-doubles (limo ~[42 10]))
|
||||
!> (~(gas by m-uno) [10 20]~)
|
||||
:: Checks appending >1 elements
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (map-of-doubles (limo ~[6 9 3 4 5 7]))
|
||||
!> (~(gas by m-dos) ~[[3 6] [4 8] [5 10] [7 14]])
|
||||
:: Checks concatenating existing elements
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-des
|
||||
!> (~(gas by m-des) ~[[3 6] [4 8] [5 10] [7 14]])
|
||||
==
|
||||
::
|
||||
:: Test grab value by key
|
||||
::
|
||||
++ test-map-get ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(get by m-nul) 6)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(get by m-des) 9)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> `14
|
||||
!> (~(get by m-des) 7)
|
||||
==
|
||||
::
|
||||
:: Test need value by key
|
||||
::
|
||||
++ test-map-got ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%- expect-fail
|
||||
|. (~(got by m-nul) 6)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%- expect-fail
|
||||
|. (~(got by m-des) 9)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 14
|
||||
!> (~(got by m-des) 7)
|
||||
==
|
||||
::
|
||||
:: Test fall value by key
|
||||
::
|
||||
++ test-map-gut ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 42
|
||||
!> (~(gut by m-nul) 6 42)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 42
|
||||
!> (~(gut by m-des) 9 42)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 14
|
||||
!> (~(gut by m-des) 7 42)
|
||||
==
|
||||
::
|
||||
:: Test +has: does :b exist in :a?
|
||||
::
|
||||
++ test-map-has ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(has by m-nul) 6)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(has by m-des) 9)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(has by m-des) 7)
|
||||
==
|
||||
::
|
||||
:: Test intersection
|
||||
::
|
||||
++ test-map-int ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(int by m-nul) m-des)
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(int by m-des) m-nul)
|
||||
:: Checks with all keys different
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(int by m-dos) m-uno)
|
||||
:: Checks success (total intersection)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-asc
|
||||
!> (~(int by m-asc) m-des)
|
||||
:: Checks success (partial intersection)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (map-of-doubles (limo ~[1 7 4 6]))
|
||||
!> (~(int by m-des) m-dup)
|
||||
:: Checks replacing value from b
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my [6 99]~)
|
||||
!> (~(int by m-dos) (my [6 99]~))
|
||||
==
|
||||
::
|
||||
:: Test search for a specific key and modifies
|
||||
:: its value with the result of the provided gate
|
||||
::
|
||||
++ test-map-jab ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%- expect-fail
|
||||
|. (~(jab by m-nul) 2 dec)
|
||||
:: Checks success, by modifying
|
||||
:: [2 4] to [2 3]
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[1 2] [2 3] [3 6] [4 8] [5 10] [6 12] [7 14]])
|
||||
!> (~(jab by m-asc) 2 dec)
|
||||
==
|
||||
::
|
||||
:: Test produce set of keys
|
||||
::
|
||||
++ test-map-key ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> ~(key by m-nul)
|
||||
:: Checks when creating a map from a list with duplicates
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy ~[1 1 7 4 6 9 4])
|
||||
!> ~(key by m-dup)
|
||||
:: Checks correctness
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy ~[1 2 3 4 5 6 7])
|
||||
!> ~(key by m-des)
|
||||
==
|
||||
::
|
||||
:: Test add key-value pair with validation (the value is a nonempty unit)
|
||||
::
|
||||
++ test-map-mar ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my [6 12]~)
|
||||
!> (~(mar by m-nul) 6 `12)
|
||||
:: Checks with empty value (deletes the key)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (~(del by m-des) 6)
|
||||
!> (~(mar by m-des) 6 ~)
|
||||
:: Checks success (when key exists)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[6 12] [9 99]])
|
||||
!> (~(mar by m-dos) 9 `99)
|
||||
:: Checks success (when key does not exist)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (~(put by m-des) [90 23])
|
||||
!> (~(mar by m-des) 90 `23)
|
||||
==
|
||||
::
|
||||
:: Test add key-value pair
|
||||
::
|
||||
++ test-map-put ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my [6 12]~)
|
||||
!> (~(put by m-nul) 6 12)
|
||||
:: Checks with existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[6 99] [9 18]])
|
||||
!> (~(put by m-dos) 6 99)
|
||||
:: Checks success (new key)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[42 84] [9 99]])
|
||||
!> (~(put by m-uno) 9 99)
|
||||
==
|
||||
::
|
||||
:: Test replace by product
|
||||
::
|
||||
++ test-map-rep ^- tang
|
||||
:: Accumulates differences between keys and values
|
||||
::
|
||||
=/ rep-gate |=([a=[@ @] b=@] (add b (sub +.a -.a)))
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> b=0
|
||||
!> (~(rep by m-nul) rep-gate)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
:: m-asc => {[5 10] [7 14] [6 12] [1 2] [2 4] [3 6] [4 8]}
|
||||
:: acc => 12-6+10-5+14-7+8-4+6-3+4-2+2-1 => 28
|
||||
!> b=28
|
||||
!> (~(rep by m-asc) rep-gate)
|
||||
==
|
||||
::
|
||||
:: Test Test transform + product
|
||||
::
|
||||
++ test-map-rib ^- tang
|
||||
:: Accumulates multiples in an array and drains the pairs
|
||||
:: whose values are double of their keys.
|
||||
::
|
||||
=/ rib-gate
|
||||
|= [a=[@ @] acc=(list @)]
|
||||
:- (weld acc ~[(div +.a -.a)])
|
||||
?: =(2 (div +.a -.a))
|
||||
[-.a 0]
|
||||
a
|
||||
=/ list-of-2s (reap 7 2)
|
||||
=/ zeroed-map (my ~[[1 0] [2 0] [3 0] [4 0] [5 0] [6 0] [7 0]])
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> [~ ~]
|
||||
!> (~(rib by m-nul) *(list @) rib-gate)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> [list-of-2s zeroed-map]
|
||||
!> (~(rib by m-asc) *(list @) rib-gate)
|
||||
==
|
||||
::
|
||||
:: Test apply gate to values
|
||||
::
|
||||
++ test-map-run ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(run by m-nul) dec)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[1 1] [2 3] [3 5] [4 7] [5 9] [6 11] [7 13]])
|
||||
!> (~(run by m-asc) dec)
|
||||
==
|
||||
::
|
||||
:: Test apply gate to nodes
|
||||
::
|
||||
++ test-map-rut ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(rut by m-nul) add)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[1 3] [2 6] [3 9] [4 12] [5 15] [6 18] [7 21]])
|
||||
!> (~(rut by m-asc) add)
|
||||
==
|
||||
::
|
||||
:: Test listify pairs
|
||||
::
|
||||
++ test-map-tap ^- tang
|
||||
=/ by-key |=([[k=@ v=@] [q=@ w=@]] (gth k q))
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> ~(tap by ~)
|
||||
:: Checks success with 2 pairs
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sort ~[[9 18] [6 12]] by-key)
|
||||
!> (sort ~(tap by m-dos) by-key)
|
||||
:: Checks success with 7 pairs
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sort ~[[1 2] [2 4] [3 6] [4 8] [5 10] [7 14] [6 12]] by-key)
|
||||
!> (sort ~(tap by m-asc) by-key)
|
||||
:: Checks success with 5 pairs (from list with duplicates)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sort ~[[7 14] [6 12] [9 18] [1 2] [4 8]] by-key)
|
||||
!> (sort ~(tap by m-dup) by-key)
|
||||
==
|
||||
::
|
||||
:: Test the union of maps
|
||||
::
|
||||
++ test-map-uni ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map (a or b)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-des
|
||||
!> (~(uni by m-nul) m-des)
|
||||
%+ expect-eq
|
||||
!> m-des
|
||||
!> (~(uni by m-des) m-nul)
|
||||
:: Checks with disjoint keys
|
||||
::
|
||||
=/ keys (limo ~[1 2 3 4 5 6 7 8])
|
||||
=/ a=(map @ @) (map-of-doubles (scag 4 keys))
|
||||
=/ b=(map @ @) (map-of-doubles (slag 4 keys))
|
||||
%+ expect-eq
|
||||
!> (map-of-doubles keys)
|
||||
!> (~(uni by a) b)
|
||||
:: Checks union of sets with all keys equal
|
||||
::
|
||||
%+ expect-eq
|
||||
!> m-asc
|
||||
!> (~(uni by m-asc) m-des)
|
||||
:: Checks union with value replacement from b
|
||||
::
|
||||
=/ c=(map @ @) (my [1 12]~)
|
||||
=/ d=(map @ @) (my [1 24]~)
|
||||
%+ expect-eq
|
||||
!> d
|
||||
!> (~(uni by c) d)
|
||||
==
|
||||
::
|
||||
:: Test general union
|
||||
::
|
||||
++ test-map-uno ^- tang
|
||||
=/ union-gate |=([k=@ v=@ w=@] (add v w))
|
||||
;: weld
|
||||
:: +uno:by arm test
|
||||
::
|
||||
:: Checks with empty map (a or b)
|
||||
::
|
||||
%- expect-fail
|
||||
|. ((~(uno by m-nul) m-des) union-gate)
|
||||
%+ expect-eq
|
||||
!> m-des
|
||||
!> ((~(uno by m-des) m-nul) union-gate)
|
||||
:: Checks with all keys different
|
||||
::
|
||||
=/ keys (limo ~[1 2 3 4 5 6 7 8])
|
||||
=/ a=(map @ @) (map-of-doubles (scag 4 keys))
|
||||
=/ b=(map @ @) (map-of-doubles (slag 4 keys))
|
||||
%+ expect-eq
|
||||
!> (map-of-doubles keys)
|
||||
!> ((~(uno by a) b) union-gate)
|
||||
:: Checks total union
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[1 4] [2 8] [3 12] [4 16] [5 20] [6 24] [7 28]])
|
||||
!> ((~(uno by m-asc) m-des) union-gate)
|
||||
:: Checks partial union
|
||||
::
|
||||
=/ a=(map @ @) (my ~[[1 9] [7 3] [8 5]])
|
||||
=/ b=(map @ @) (my ~[[1 2] [7 2]])
|
||||
%+ expect-eq
|
||||
!> (my ~[[1 11] [7 5] [8 5]])
|
||||
!> ((~(uno by a) b) union-gate)
|
||||
==
|
||||
::
|
||||
:: Test apply gate to nodes (duplicates +rut)
|
||||
::
|
||||
++ test-map-urn ^- tang
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(urn by m-nul) add)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (my ~[[1 3] [2 6] [3 9] [4 12] [5 15] [6 18] [7 21]])
|
||||
!> (~(urn by m-asc) add)
|
||||
==
|
||||
::
|
||||
:: Test produce list of vals
|
||||
::
|
||||
++ test-map-val ^- tang
|
||||
=/ double |=(e=@ (mul 2 e))
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> ~(val by m-nul)
|
||||
:: Checks when creating a set from a list with duplicates
|
||||
::
|
||||
=/ a=(list @) ~(tap in (sy ~[1 1 7 4 6 9 4]))
|
||||
%+ expect-eq
|
||||
!> (sort (turn a double) gth)
|
||||
!> (sort ~(val by m-dup) gth)
|
||||
:: Checks success
|
||||
::
|
||||
=/ b=(list @) ~(tap in (sy (gulf 1 7)))
|
||||
%+ expect-eq
|
||||
!> (sort (turn b double) gth)
|
||||
!> (sort ~(val by m-asc) gth)
|
||||
==
|
||||
::
|
||||
:: Tests the size of map
|
||||
::
|
||||
++ test-map-wyt ^- tang
|
||||
:: Runs all the tests in the suite
|
||||
::
|
||||
=/ sizes=(list @)
|
||||
%+ turn m-lis
|
||||
|=(m=(map @ @) ~(wyt by m))
|
||||
%+ expect-eq
|
||||
!> sizes
|
||||
!> (limo ~[0 1 2 2 7 7 7 5])
|
||||
--
|
@ -30,6 +30,6 @@
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> ((soft (qeu)) [98 [97 ~ ~] [100 ~ [99 ~ ~]]])
|
||||
!> ((soft (qeu)) [97 [98 ~ ~] [100 ~ [99 ~ ~]]])
|
||||
==
|
||||
--
|
||||
|
357
pkg/arvo/tests/sys/hoon/qeu.hoon
Normal file
357
pkg/arvo/tests/sys/hoon/qeu.hoon
Normal file
@ -0,0 +1,357 @@
|
||||
:: Tests for +to (queue logic)
|
||||
::
|
||||
/+ *test
|
||||
::
|
||||
=> :: Test Data
|
||||
::
|
||||
|%
|
||||
+| %test-suite
|
||||
++ l-uno ~[42]
|
||||
++ l-dos ~[6 9]
|
||||
++ l-tre ~[1 0 1]
|
||||
++ l-tri ~[1 2 3]
|
||||
++ l-tra ~[3 2 1]
|
||||
++ l-asc ~[1 2 3 4 5 6 7]
|
||||
++ l-des ~[7 6 5 4 3 2 1]
|
||||
++ l-uns ~[1 6 3 5 7 2 4]
|
||||
++ l-dup ~[1 1 7 4 6 9 4]
|
||||
:: Each entry in the test suite is tagged to identify
|
||||
:: the +to arm that fails with a specific queue.
|
||||
::
|
||||
++ q-nul [%nul (~(gas to *(qeu)) ~)]
|
||||
++ q-uno [%uno (~(gas to *(qeu)) l-uno)]
|
||||
++ q-dos [%dos (~(gas to *(qeu)) l-dos)]
|
||||
++ q-tre [%tre (~(gas to *(qeu)) l-tre)]
|
||||
++ q-tri [%tri (~(gas to *(qeu)) l-tri)]
|
||||
++ q-tra [%tra (~(gas to *(qeu)) l-tra)]
|
||||
++ q-asc [%asc (~(gas to *(qeu)) l-asc)]
|
||||
++ q-des [%des (~(gas to *(qeu)) l-des)]
|
||||
++ q-uns [%uns (~(gas to *(qeu)) l-uns)]
|
||||
++ q-dup [%dup (~(gas to *(qeu)) l-dup)]
|
||||
+| %grouped-data
|
||||
++ queues ^- (list [term (qeu)])
|
||||
:~ q-uno q-dos q-tre
|
||||
q-tri q-tra q-asc
|
||||
q-des q-uns q-dup
|
||||
==
|
||||
++ lists ^- (list (list))
|
||||
:~ l-uno l-dos l-tre
|
||||
l-tri l-tra l-asc
|
||||
l-des l-uns l-dup
|
||||
==
|
||||
--
|
||||
:: Testing arms
|
||||
::
|
||||
|%
|
||||
:: Test check correctness
|
||||
::
|
||||
++ test-queue-apt ^- tang
|
||||
:: Manually constructed queues with predefined vertical ordering
|
||||
:: for the following three elements (1, 2, 3) the priorities are:
|
||||
:: > (mug (mug 1))
|
||||
:: 1.405.103.437
|
||||
:: > (mug (mug 2))
|
||||
:: 1.200.431.393
|
||||
:: > (mug (mug 3))
|
||||
:: 1.576.941.407
|
||||
::
|
||||
:: and the ordering 2 < 1 < 3
|
||||
:: a correctly balanced tree stored as a min-heap
|
||||
:: should have 2 as the root
|
||||
::
|
||||
=/ balanced-a=(qeu @) [2 [3 ~ ~] [1 ~ ~]]
|
||||
=/ balanced-b=(qeu @) [2 [1 ~ ~] [3 ~ ~]]
|
||||
=/ unbalanced-a=(qeu @) [3 [2 ~ ~] [1 ~ ~]]
|
||||
=/ unbalanced-b=(qeu @) [1 [3 ~ ~] [2 ~ ~]]
|
||||
=/ unbalanced-c=(qeu @) [3 [1 ~ ~] [2 ~ ~]]
|
||||
=/ unbalanced-d=(qeu @) [3 ~ [2 ~ ~]]
|
||||
=/ unbalanced-e=(qeu @) [3 [1 ~ ~] ~]
|
||||
;: weld
|
||||
%+ expect-eq
|
||||
!> [%b-a %.y]
|
||||
!> [%b-a ~(apt to balanced-a)]
|
||||
%+ expect-eq
|
||||
!> [%b-b %.y]
|
||||
!> [%b-b ~(apt to balanced-b)]
|
||||
%+ expect-eq
|
||||
!> [%u-a %.n]
|
||||
!> [%u-a ~(apt to unbalanced-a)]
|
||||
%+ expect-eq
|
||||
!> [%u-b %.n]
|
||||
!> [%u-b ~(apt to unbalanced-b)]
|
||||
%+ expect-eq
|
||||
!> [%u-c %.n]
|
||||
!> [%u-c ~(apt to unbalanced-c)]
|
||||
%+ expect-eq
|
||||
!> [%u-d %.n]
|
||||
!> [%u-d ~(apt to unbalanced-d)]
|
||||
%+ expect-eq
|
||||
!> [%u-e %.n]
|
||||
!> [%u-e ~(apt to unbalanced-e)]
|
||||
==
|
||||
::
|
||||
:: Test balancing the queue
|
||||
::
|
||||
++ test-queue-bal ^- tang
|
||||
:: Manually created queues explicitly unbalanced
|
||||
:: p(2) < p(1) < p(3)
|
||||
:: that places nodes with higher priority as the root
|
||||
::
|
||||
=/ unbalanced-a=(qeu @) [3 [2 ~ ~] [1 ~ ~]]
|
||||
=/ unbalanced-b=(qeu @) [1 [3 ~ ~] [2 ~ ~]]
|
||||
=/ unbalanced-c=(qeu @) [3 [1 ~ ~] [2 ~ ~]]
|
||||
;: weld
|
||||
%+ expect-eq
|
||||
!> [%u-a %.y]
|
||||
!> [%u-a ~(apt to ~(bal to unbalanced-a))]
|
||||
%+ expect-eq
|
||||
!> [%u-b %.y]
|
||||
!> [%u-b ~(apt to ~(bal to unbalanced-b))]
|
||||
%+ expect-eq
|
||||
!> [%u-c %.y]
|
||||
!> [%u-c ~(apt to ~(bal to unbalanced-c))]
|
||||
==
|
||||
::
|
||||
:: Test max depth of queue
|
||||
::
|
||||
++ test-queue-dep ^- tang
|
||||
:: Manually created queues with known depth
|
||||
::
|
||||
=/ length-a=(qeu @) [3 [2 ~ ~] [1 ~ ~]]
|
||||
=/ length-b=(qeu @) [1 ~ ~]
|
||||
=/ length-c=(qeu @) [5 ~ [4 ~ [2 [3 ~ ~] [1 ~ ~]]]]
|
||||
=/ length-d=(qeu @) [5 [4 [2 [3 ~ ~] [1 ~ ~]] ~] ~]
|
||||
=/ length-e=(qeu @) [5 [4 [2 ~ [1 ~ ~]] ~] [3 ~ ~]]
|
||||
=/ length-f=(qeu @) [5 [4 [1 ~ ~] [9 ~ ~]] [3 [6 ~ ~] [7 ~ ~]]]
|
||||
;: weld
|
||||
%+ expect-eq
|
||||
!> [%l-a 2]
|
||||
!> [%l-a ~(dep to length-a)]
|
||||
%+ expect-eq
|
||||
!> [%l-b 1]
|
||||
!> [%l-b ~(dep to length-b)]
|
||||
%+ expect-eq
|
||||
!> [%l-c 4]
|
||||
!> [%l-c ~(dep to length-c)]
|
||||
%+ expect-eq
|
||||
!> [%l-d 4]
|
||||
!> [%l-d ~(dep to length-d)]
|
||||
%+ expect-eq
|
||||
!> [%l-e 4]
|
||||
!> [%l-e ~(dep to length-e)]
|
||||
%+ expect-eq
|
||||
!> [%l-f 3]
|
||||
!> [%l-f ~(dep to length-f)]
|
||||
==
|
||||
::
|
||||
:: Test insert list into queue
|
||||
::
|
||||
++ test-queue-gas ^- tang
|
||||
=/ actual=(list [term ?])
|
||||
%+ turn queues
|
||||
|= [t=term s=(qeu)]
|
||||
:: We use +apt to check the correctness
|
||||
:: of the queues created with +gas
|
||||
::
|
||||
[t ~(apt to s)]
|
||||
%- zing
|
||||
;: weld
|
||||
:: Checks with all tests in the suite
|
||||
::
|
||||
%+ turn actual
|
||||
|= [t=term f=?]
|
||||
%+ expect-eq
|
||||
!> t^&
|
||||
!> t^f
|
||||
:: Checks appending >1 elements
|
||||
::
|
||||
:_ ~
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> ~(apt to (~(gas to +:q-dos) ~[9 10]))
|
||||
:: Checks adding existing elements
|
||||
::
|
||||
:_ ~
|
||||
%+ expect-eq
|
||||
!> (~(gas to *(qeu)) (weld (gulf 1 7) (gulf 1 3)))
|
||||
!> (~(gas to +:q-asc) (gulf 1 3))
|
||||
==
|
||||
::
|
||||
:: Test getting head-rest pair
|
||||
::
|
||||
++ test-queue-get ^- tang
|
||||
=/ expected=(map term [@ (qeu)])
|
||||
%- my
|
||||
:~ uno+[42 ~]
|
||||
dos+[6 (~(gas to *(qeu)) ~[9])]
|
||||
tre+[1 (~(gas to *(qeu)) ~[0 1])]
|
||||
tri+[1 (~(gas to *(qeu)) ~[2 3])]
|
||||
tra+[3 (~(gas to *(qeu)) ~[2 1])]
|
||||
asc+[1 (~(gas to *(qeu)) ~[2 3 4 5 6 7])]
|
||||
des+[7 (~(gas to *(qeu)) ~[6 5 4 3 2 1])]
|
||||
uns+[1 (~(gas to *(qeu)) ~[6 3 5 7 2 4])]
|
||||
dup+[1 (~(gas to *(qeu)) ~[1 7 4 6 9 4])]
|
||||
==
|
||||
=/ pairs=(list [term [* (qeu)]])
|
||||
%+ turn queues
|
||||
|=([t=term q=(qeu)] [t ~(get to q)])
|
||||
%- zing
|
||||
;: weld
|
||||
:: All tests in the suite
|
||||
::
|
||||
%+ turn pairs
|
||||
|= [t=term p=[* (qeu)]]
|
||||
%+ expect-eq
|
||||
!> t^(~(got by expected) t)
|
||||
!> t^p
|
||||
:: Expects crash on empty list
|
||||
::
|
||||
:_ ~
|
||||
%- expect-fail
|
||||
|. ~(get to +:q-nul)
|
||||
==
|
||||
::
|
||||
:: Test removing the root (more specialized balancing operation)
|
||||
::
|
||||
++ test-queue-nip ^- tang
|
||||
=/ actual=(list [term ?])
|
||||
%+ turn queues
|
||||
:: The queue representation follows vertical ordering
|
||||
:: of the tree nodes as a min-heap
|
||||
:: [i.e. priority(parent node) < priority(children)]
|
||||
:: after nip we check that the resulting tree is balanced
|
||||
::
|
||||
|=([t=term q=(qeu)] [t ~(apt to ~(nip to q))])
|
||||
%- zing
|
||||
;: weld
|
||||
:: All tests in the suite
|
||||
::
|
||||
%+ turn actual
|
||||
|= [t=term f=?]
|
||||
(expect-eq !>(t^&) !>(t^f))
|
||||
:: Expects crash on empty list
|
||||
::
|
||||
:_ ~
|
||||
%- expect-fail
|
||||
|. ~(nap to +:q-nul)
|
||||
==
|
||||
::
|
||||
:: Test removing the root
|
||||
::
|
||||
:: Current comment at L:1788 to %/sys/hoon/hoon.hoon is wrong
|
||||
:: For a longer explanation read:
|
||||
:: https://github.com/urbit/urbit/issues/1577#issuecomment-483845590
|
||||
::
|
||||
++ test-queue-nap ^- tang
|
||||
=/ actual=(list [term ?])
|
||||
%+ turn queues
|
||||
:: The queue representation follows vertical ordering
|
||||
:: of the tree nodes as a min-heap
|
||||
:: [i.e. priority(parent node) < priority(children)]
|
||||
:: after nip we check that the resulting tree is balanced
|
||||
::
|
||||
|=([t=term q=(qeu)] [t ~(apt to ~(nap to q))])
|
||||
%- zing
|
||||
;: weld
|
||||
:: All tests in the suite
|
||||
::
|
||||
%+ turn actual
|
||||
|= [t=term f=?]
|
||||
(expect-eq !>(t^&) !>(t^f))
|
||||
:: Expects crash on empty list
|
||||
::
|
||||
:_ ~
|
||||
%- expect-fail
|
||||
|. ~(nap to +:q-nul)
|
||||
==
|
||||
::
|
||||
:: Test inserting new tail
|
||||
::
|
||||
++ test-queue-put ^- tang
|
||||
=/ q-uno (~(gas to *(qeu)) ~[42])
|
||||
=/ q-asc (~(gas to *(qeu)) (gulf 1 7))
|
||||
=/ q-dos (~(gas to *(qeu)) ~[42 43])
|
||||
;: weld
|
||||
:: Checks with empty queue
|
||||
::
|
||||
%+ expect-eq
|
||||
!> q-uno
|
||||
!> (~(put to *(qeu)) 42)
|
||||
:: Checks putting existing element
|
||||
::
|
||||
=/ q-dup (~(gas to *(qeu)) ~[1 2 3 4 5 6 7 6])
|
||||
%+ expect-eq
|
||||
!> q-dup
|
||||
!> (~(put to q-asc) 6)
|
||||
:: Checks putting a new element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (~(gas to *(qeu)) (gulf 1 8))
|
||||
!> (~(put to q-asc) 8)
|
||||
==
|
||||
::
|
||||
:: Test producing a queue a as a list from front to back
|
||||
::
|
||||
++ test-queue-tap ^- tang
|
||||
:: We ran all queues in the suite against the corresponding lists
|
||||
::
|
||||
=/ queues=(list (qeu))
|
||||
%+ turn lists
|
||||
|=(iq=(list) (~(gas to *(qeu)) iq))
|
||||
=/ actual=(list (list))
|
||||
%+ turn queues
|
||||
|=(iq=(qeu) ~(tap to iq))
|
||||
(expect-eq !>(lists) !>(actual))
|
||||
::
|
||||
:: Test producing the head of the queue
|
||||
::
|
||||
++ test-queue-top ^- tang
|
||||
:: In order to know beforehand which element of the +qeu will become
|
||||
:: the head, we need to look at the way new nodes are added to the
|
||||
:: tree and how it's rebalanced.
|
||||
::
|
||||
:: New nodes are appended to the left-most branch of the tree, and
|
||||
:: then the resulting tree will be balanced following the heap property.
|
||||
:: The idea is that the balancing will be applied to all the subtrees,
|
||||
:: starting from the node whose left branch is the new node that we
|
||||
:: have appended. We will then perform certain tree rotations, depending
|
||||
:: on the different priorities of the nodes considered.
|
||||
::
|
||||
:: If the new node has lower priority, a right-rotation is performed.
|
||||
:: This will push the node (which was the first node) to the right
|
||||
:: branch and balance that sub-branch, while promoting the node in the
|
||||
:: left branch as the new node.
|
||||
::
|
||||
:: If the new node has higher priority, we check the right branch to
|
||||
:: ensure that the heap-priority is conserved. In the case of the first
|
||||
:: insert, the right branch is empty, therefore, no rotations are needed.
|
||||
::
|
||||
:: This means that the first node inserted in the +qeu will be located
|
||||
:: either as the node of the +qeu, or in the right-most branch.
|
||||
::
|
||||
:: By inspecting +top:to we can see that it perfoms a traversal on the right
|
||||
:: branch of the tree returning the last node whose right branch is null,
|
||||
:: which is what we are looking for.
|
||||
::
|
||||
=/ expected=(map term @)
|
||||
(my ~[uno+42 dos+6 tre+1 tri+1 tra+3 asc+1 des+7 uns+1 dup+1])
|
||||
=/ heads=(list [term (unit)])
|
||||
%+ turn queues
|
||||
|=([t=term iq=(qeu)] [t ~(top to iq)])
|
||||
%- zing
|
||||
;: weld
|
||||
:: All the tests in the suite
|
||||
::
|
||||
%+ turn heads
|
||||
|= [t=term u=(unit)]
|
||||
%+ expect-eq
|
||||
!> t^(~(get by expected) t)
|
||||
!> t^u
|
||||
:_ ~
|
||||
:: Top of an empty queue is ~
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> ~(top to +:q-nul)
|
||||
==
|
||||
--
|
504
pkg/arvo/tests/sys/hoon/set.hoon
Normal file
504
pkg/arvo/tests/sys/hoon/set.hoon
Normal file
@ -0,0 +1,504 @@
|
||||
:: Tests for +in (set logic)
|
||||
::
|
||||
/+ *test
|
||||
::
|
||||
:: Testing arms
|
||||
::
|
||||
|%
|
||||
:: Test logical AND
|
||||
::
|
||||
++ test-set-all ^- tang
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(all in ~) |=(* &))
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(all in ~) |=(* |))
|
||||
:: Checks one element fails
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(all in (sy ~[1])) |=(e=@ =(e 43)))
|
||||
:: Checks not all elements pass
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(all in s-asc) |=(e=@ (lth e 4)))
|
||||
:: Checks all element pass
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(all in s-asc) |=(e=@ (lth e 100)))
|
||||
==
|
||||
::
|
||||
:: Test logical OR
|
||||
::
|
||||
++ test-set-any ^- tang
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any in ~) |=(* &))
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any in ~) |=(* |))
|
||||
:: Checks one element fails
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(any in (sy ~[1])) |=(e=@ =(e 43)))
|
||||
:: Checks >1 element success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(any in s-asc) |=(e=@ (lth e 4)))
|
||||
:: Checks all element success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(any in s-asc) |=(e=@ (lth e 100)))
|
||||
==
|
||||
::
|
||||
:: Test check correctness
|
||||
::
|
||||
++ test-set-apt ^- tang
|
||||
:: Manually constructed sets with predefined vertical/horizontal
|
||||
:: ordering
|
||||
::
|
||||
:: for the following three elements (1, 2, 3) the vertical priorities are:
|
||||
:: > (mug (mug 1))
|
||||
:: 1.405.103.437
|
||||
:: > (mug (mug 2))
|
||||
:: 1.200.431.393
|
||||
:: > (mug (mug 3))
|
||||
:: 1.576.941.407
|
||||
::
|
||||
:: and the ordering 2 < 1 < 3
|
||||
:: a correctly balanced tree stored as a min-heap
|
||||
:: should have node=2 as the root
|
||||
::
|
||||
:: The horizontal priorities are:
|
||||
:: > (mug 1)
|
||||
:: 1.901.865.568
|
||||
:: > (mug 2)
|
||||
:: 1.904.972.904
|
||||
:: > (mug 3)
|
||||
:: 1.923.673.882
|
||||
::
|
||||
:: and the ordering 1 < 2 < 3.
|
||||
:: 1 should be in the left brach and 3 in the right one.
|
||||
::
|
||||
=/ balanced-a=(set @) [2 [1 ~ ~] [3 ~ ~]]
|
||||
:: Doesn't follow vertical ordering
|
||||
::
|
||||
=/ unbalanced-a=(set @) [1 [2 ~ ~] [3 ~ ~]]
|
||||
=/ unbalanced-b=(set @) [1 ~ [2 ~ ~]]
|
||||
=/ unbalanced-c=(set @) [1 [2 ~ ~] ~]
|
||||
:: Doesn't follow horizontal ordering
|
||||
::
|
||||
=/ unbalanced-d=(set @) [2 [3 ~ ~] [1 ~ ~]]
|
||||
:: Doesn't follow horizontal & vertical ordering
|
||||
::
|
||||
=/ unbalanced-e=(set @) [1 [3 ~ ~] [2 ~ ~]]
|
||||
;: weld
|
||||
%+ expect-eq
|
||||
!> [%b-a %.y]
|
||||
!> [%b-a ~(apt in balanced-a)]
|
||||
%+ expect-eq
|
||||
!> [%u-a %.n]
|
||||
!> [%u-a ~(apt in unbalanced-a)]
|
||||
%+ expect-eq
|
||||
!> [%u-b %.n]
|
||||
!> [%u-b ~(apt in unbalanced-b)]
|
||||
%+ expect-eq
|
||||
!> [%u-c %.n]
|
||||
!> [%u-c ~(apt in unbalanced-c)]
|
||||
%+ expect-eq
|
||||
!> [%u-d %.n]
|
||||
!> [%u-d ~(apt in unbalanced-d)]
|
||||
%+ expect-eq
|
||||
!> [%u-e %.n]
|
||||
!> [%u-e ~(apt in unbalanced-e)]
|
||||
==
|
||||
::
|
||||
:: Test splits a in b
|
||||
::
|
||||
++ test-set-bif ^- tang
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
=/ s-nul=(set @) *(set @)
|
||||
=/ splits-a=[(set) (set)] (~(bif in s-asc) 99)
|
||||
=/ splits-b=[(set) (set)] (~(bif in s-asc) 6)
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> [~ ~]
|
||||
!> (~(bif in s-nul) 1)
|
||||
:: Checks bifurcating in non-existing element
|
||||
::
|
||||
:: The traversal of the +map is done comparing the double +mug
|
||||
:: of the added node and the existing one from the tree.
|
||||
:: Because of this, the search will stop at different leaves,
|
||||
:: based on the value of the hash, therefore the right and left
|
||||
:: maps that are returned can be different
|
||||
:: (null or a less than the total number of nodes)
|
||||
:: The best way to check is that the sum of the number of nodes
|
||||
:: in both maps are the same as before, and that both returned
|
||||
:: sets are correct
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 7
|
||||
!> (add ~(wyt in -.splits-a) ~(wyt in +.splits-a))
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> &(~(apt in -.splits-a) ~(apt in +.splits-a))
|
||||
:: Checks splitting in existing element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 6
|
||||
!> (add ~(wyt in -.splits-b) ~(wyt in +.splits-b))
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> &(~(apt in -.splits-b) ~(apt in +.splits-b))
|
||||
=/ left (~(has in -.splits-b) 6)
|
||||
=/ right (~(has in +.splits-b) 6)
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> &(left right)
|
||||
==
|
||||
::
|
||||
:: Test b without any a
|
||||
::
|
||||
++ test-set-del ^- tang
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(del in ~) 1)
|
||||
:: Checks deleting non-existing element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(del in s-asc) 99)
|
||||
:: Checks deleting the only element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(del in (sy ~[1])) 1)
|
||||
:: Checks deleting one element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy (gulf 1 6))
|
||||
!> (~(del in s-asc) 7)
|
||||
==
|
||||
::
|
||||
:: Test difference
|
||||
::
|
||||
++ test-set-dif ^- tang
|
||||
=/ s-des=(set @) (sy (flop (gulf 1 7)))
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
=/ s-dos=(set @) (sy ~[8 9])
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dif in *(set)) ~)
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(dif in s-asc) ~)
|
||||
:: Checks with equal sets
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dif in s-asc) s-des)
|
||||
:: Checks no elements in common
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-dos
|
||||
!> (~(dif in s-dos) s-asc)
|
||||
:: Checks with sets of diferent size
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-dos
|
||||
!> (~(dif in (sy ~[1 8 9])) s-asc)
|
||||
==
|
||||
::
|
||||
:: Test axis of a in b
|
||||
::
|
||||
++ test-set-dig ^- tang
|
||||
=/ custom [2 [1 ~ ~] [3 ~ ~]]
|
||||
=/ custom-vase !>(custom)
|
||||
=/ manual-set=(set @) custom
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dig in *(set)) 6)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(dig in manual-set) 9)
|
||||
:: Checks success via tree addressing. It uses the returned axis
|
||||
:: to address the raw noun and check that it gives the corresponding
|
||||
:: value.
|
||||
::
|
||||
%+ expect-eq
|
||||
!> 1
|
||||
!> +:(slot (need (~(dig in manual-set) 1)) custom-vase)
|
||||
%+ expect-eq
|
||||
!> 2
|
||||
!> +:(slot (need (~(dig in manual-set) 2)) custom-vase)
|
||||
%+ expect-eq
|
||||
!> 3
|
||||
!> +:(slot (need (~(dig in manual-set) 3)) custom-vase)
|
||||
==
|
||||
::
|
||||
:: Test concatenate
|
||||
::
|
||||
++ test-set-gas ^- tang
|
||||
:: Uses +apt to check the correctness
|
||||
:: of the sets created with +gas
|
||||
::
|
||||
=+ |%
|
||||
+| %test-suite
|
||||
++ s-uno (~(gas in *(set)) ~[42])
|
||||
++ s-dos (~(gas in *(set)) ~[6 9])
|
||||
++ s-tre (~(gas in *(set)) ~[1 0 1])
|
||||
++ s-asc (~(gas in *(set)) ~[1 2 3 4 5 6 7])
|
||||
++ s-des (~(gas in *(set)) ~[7 6 5 4 3 2 1])
|
||||
++ s-uns (~(gas in *(set)) ~[1 6 3 5 7 2 4])
|
||||
++ s-dup (~(gas in *(set)) ~[1 1 7 4 6 9 4])
|
||||
++ s-nul (~(gas in *(set)) ~)
|
||||
--
|
||||
=/ s-lis=(list (set)) ~[s-nul s-uno s-dos s-tre s-asc s-des s-uns s-dup]
|
||||
=/ actual=?
|
||||
%+ roll s-lis
|
||||
|= [s=(set) b=?]
|
||||
^- ?
|
||||
&(b ~(apt in s))
|
||||
;: weld
|
||||
:: Checks with all tests in the suite
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> actual
|
||||
:: Checks appending >1 elements
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> ~(apt in (~(gas in s-dos) ~[9 10]))
|
||||
:: Checks concatenating existing elements
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(gas in s-asc) (gulf 1 3))
|
||||
==
|
||||
::
|
||||
:: Test +has: does :b exist in :a?
|
||||
::
|
||||
++ test-set-has ^- tang
|
||||
=/ s-nul=(set @) *(set @)
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(has in s-nul) 6)
|
||||
:: Checks with non-existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.n
|
||||
!> (~(has in s-asc) 9)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> %.y
|
||||
!> (~(has in s-asc) 7)
|
||||
==
|
||||
::
|
||||
:: Test intersection
|
||||
::
|
||||
++ test-set-int ^- tang
|
||||
=/ s-nul=(set @) *(set @)
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
=/ s-des=(set @) (sy (flop (gulf 1 7)))
|
||||
=/ s-dos=(set @) (sy (gulf 8 9))
|
||||
=/ s-dup (sy ~[1 1 4 1 3 5 9 4])
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(int in s-nul) s-asc)
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(int in s-asc) s-nul)
|
||||
:: Checks with all elements different
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(int in s-dos) s-asc)
|
||||
:: Checks success (total intersection)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(int in s-asc) s-des)
|
||||
:: Checks success (partial intersection)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy ~[9])
|
||||
!> (~(int in s-dos) s-dup)
|
||||
==
|
||||
::
|
||||
:: Test puts b in a, sorted
|
||||
::
|
||||
++ test-set-put ^- tang
|
||||
=/ s-nul=(set @) *(set @)
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy ~[6])
|
||||
!> (~(put in s-nul) 6)
|
||||
:: Checks with existing key
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(put in s-asc) 6)
|
||||
:: Checks adding new element
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy (gulf 1 8))
|
||||
!> (~(put in s-asc) 8)
|
||||
==
|
||||
:: Test replace in product
|
||||
::
|
||||
++ test-set-rep ^- tang
|
||||
=/ s-nul=(set @) *(set @)
|
||||
=/ s-asc=(set @) (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty set
|
||||
::
|
||||
%+ expect-eq
|
||||
!> b=0
|
||||
!> (~(rep in s-nul) add)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> b=28
|
||||
!> (~(rep in s-asc) add)
|
||||
==
|
||||
::
|
||||
:: Test apply gate to values
|
||||
::
|
||||
++ test-set-run ^- tang
|
||||
=/ s-nul *(set @)
|
||||
=/ s-asc (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> (~(run in s-nul) dec)
|
||||
:: Checks success
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sy (gulf 0 6))
|
||||
!> (~(run in s-asc) dec)
|
||||
==
|
||||
::
|
||||
:: Converts a set to list
|
||||
::
|
||||
++ test-set-tap ^- tang
|
||||
=/ s-dup (sy ~[1 1 4 1 3 5 9 4])
|
||||
=/ s-asc (sy (gulf 1 7))
|
||||
;: weld
|
||||
:: Checks with empty map
|
||||
::
|
||||
%+ expect-eq
|
||||
!> ~
|
||||
!> ~(tap in *(set @))
|
||||
:: Checks with duplicates
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (sort ~[1 4 3 5 9] gth)
|
||||
!> (sort ~(tap in s-dup) gth)
|
||||
:: Checks with ascending list
|
||||
::
|
||||
%+ expect-eq
|
||||
!> (gulf 1 7)
|
||||
!> (sort ~(tap in s-asc) lth)
|
||||
==
|
||||
::
|
||||
:: Test the union of sets
|
||||
::
|
||||
++ test-set-uni ^- tang
|
||||
=/ asc=(list @) (gulf 1 7)
|
||||
=/ des=(list @) (flop (gulf 1 7))
|
||||
=/ s-des=(set @) (sy des)
|
||||
=/ s-asc=(set @) (sy asc)
|
||||
=/ s-nul=(set @) *(set @)
|
||||
;: weld
|
||||
:: Checks with empty map (a or b)
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-des
|
||||
!> (~(uni in s-nul) s-des)
|
||||
%+ expect-eq
|
||||
!> s-des
|
||||
!> (~(uni in s-des) s-nul)
|
||||
:: Checks with no intersection
|
||||
::
|
||||
=/ a=(set @) (sy (scag 4 asc))
|
||||
=/ b=(set @) (sy (slag 4 asc))
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(uni in a) b)
|
||||
:: Checks union with equal sets
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(uni in s-asc) s-des)
|
||||
:: Checks union with partial intersection
|
||||
::
|
||||
%+ expect-eq
|
||||
!> s-asc
|
||||
!> (~(uni in s-asc) (sy (gulf 1 3)))
|
||||
==
|
||||
::
|
||||
:: Tests the size of set
|
||||
::
|
||||
++ test-set-wyt ^- tang
|
||||
=+ |%
|
||||
++ s-uno (~(gas in *(set)) ~[42])
|
||||
++ s-dos (~(gas in *(set)) ~[6 9])
|
||||
++ s-tre (~(gas in *(set)) ~[1 0 1])
|
||||
++ s-asc (~(gas in *(set)) ~[1 2 3 4 5 6 7])
|
||||
++ s-des (~(gas in *(set)) ~[7 6 5 4 3 2 1])
|
||||
++ s-uns (~(gas in *(set)) ~[1 6 3 5 7 2 4])
|
||||
++ s-dup (~(gas in *(set)) ~[1 1 7 4 6 9 4])
|
||||
++ s-nul (~(gas in *(set)) ~)
|
||||
++ s-lis ~[s-nul s-uno s-dos s-tre s-asc s-des s-uns s-dup]
|
||||
--
|
||||
:: Runs all the tests in the suite
|
||||
::
|
||||
=/ sizes=(list @)
|
||||
%+ turn s-lis
|
||||
|=(s=(set) ~(wyt in s))
|
||||
%+ expect-eq
|
||||
!> sizes
|
||||
!> (limo ~[0 1 2 2 7 7 7 5])
|
||||
--
|
@ -602,7 +602,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'GET'
|
||||
'/~landscape/inner-path'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
~
|
||||
==
|
||||
^= comparator
|
||||
@ -631,7 +631,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
:* %'GET'
|
||||
'/~landscape/inner-path'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
~
|
||||
== ==
|
||||
==
|
||||
@ -985,12 +985,17 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'GET'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
~
|
||||
==
|
||||
^= expected-moves
|
||||
^- (list move:http-server-gate)
|
||||
:~ :* duct=~[/http-get-open]
|
||||
%pass
|
||||
/channel/heartbeat/'0123456789abcdef'
|
||||
[%b %wait ~1111.1.2..00.03.20]
|
||||
==
|
||||
:* duct=~[/http-get-open]
|
||||
%give
|
||||
%response
|
||||
%start
|
||||
@ -1033,9 +1038,14 @@
|
||||
call-args=[duct=~[/http-get-open] ~ %cancel-request ~]
|
||||
^= expected-moves
|
||||
^- (list move:http-server-gate)
|
||||
:: closing the channel restarts the timeout timer
|
||||
:: closing the channel cancels the sse heartbeat
|
||||
:: (initialized in results5 above) and restarts the timeout timer
|
||||
::
|
||||
:~ :* duct=~[/http-get-open] %pass
|
||||
/channel/heartbeat/'0123456789abcdef'
|
||||
%b %rest :(add ~1111.1.2 ~m3 ~s20)
|
||||
==
|
||||
:* duct=~[/http-get-open] %pass
|
||||
/channel/timeout/'0123456789abcdef'
|
||||
%b %wait :(add ~1111.1.2 ~h12 ~m4)
|
||||
== ==
|
||||
@ -1073,7 +1083,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'PUT'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
::
|
||||
:- ~
|
||||
%- as-octs:mimes:html
|
||||
@ -1173,7 +1183,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'PUT'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
::
|
||||
:- ~
|
||||
%- as-octs:mimes:html
|
||||
@ -1274,7 +1284,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'PUT'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
::
|
||||
:- ~
|
||||
%- as-octs:mimes:html
|
||||
@ -1364,12 +1374,17 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'GET'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
~
|
||||
==
|
||||
^= expected-moves
|
||||
^- (list move:http-server-gate)
|
||||
:~ :* duct=~[/http-get-open]
|
||||
%pass
|
||||
/channel/heartbeat/'0123456789abcdef'
|
||||
[%b %wait ~1111.1.2..00.03.20]
|
||||
==
|
||||
:* duct=~[/http-get-open]
|
||||
%give
|
||||
%response
|
||||
%start
|
||||
@ -1419,7 +1434,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'PUT'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
::
|
||||
:- ~
|
||||
%- as-octs:mimes:html
|
||||
@ -1556,12 +1571,17 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'GET'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
~
|
||||
==
|
||||
^= expected-moves
|
||||
^- (list move:http-server-gate)
|
||||
:~ :* duct=~[/http-get-open]
|
||||
%pass
|
||||
/channel/heartbeat/'0123456789abcdef'
|
||||
[%b %wait ~1111.1.2..00.03.20]
|
||||
==
|
||||
:* duct=~[/http-get-open]
|
||||
%give
|
||||
%response
|
||||
%start
|
||||
@ -1636,7 +1656,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'PUT'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
::
|
||||
:- ~
|
||||
%- as-octs:mimes:html
|
||||
@ -1667,9 +1687,14 @@
|
||||
call-args=[duct=~[/http-get-open] ~ %cancel-request ~]
|
||||
^= expected-moves
|
||||
^- (list move:http-server-gate)
|
||||
:: closing the channel restarts the timeout timer
|
||||
:: closing the channel cancels the sse heartbeat
|
||||
:: (initialized in results4 above) and restarts the timeout timer
|
||||
::
|
||||
:~ :* duct=~[/http-get-open] %pass
|
||||
/channel/heartbeat/'0123456789abcdef'
|
||||
%b %rest :(add ~1111.1.2 ~m3 ~s20)
|
||||
==
|
||||
:* duct=~[/http-get-open] %pass
|
||||
/channel/timeout/'0123456789abcdef'
|
||||
%b %wait :(add ~1111.1.2 ~h12 ~m6)
|
||||
== ==
|
||||
@ -1706,12 +1731,17 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'GET'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
~
|
||||
==
|
||||
^= expected-moves
|
||||
^- (list move:http-server-gate)
|
||||
:~ :* duct=~[/http-get-open]
|
||||
%pass
|
||||
/channel/heartbeat/'0123456789abcdef'
|
||||
[%b %wait ~1111.1.2..00.08.20]
|
||||
==
|
||||
:* duct=~[/http-get-open]
|
||||
%give
|
||||
%response
|
||||
%start
|
||||
@ -2079,7 +2109,7 @@
|
||||
:- 307
|
||||
:~ ['location' '/~landscape']
|
||||
:- 'set-cookie'
|
||||
'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea; Path=/; Max-Age=604800'
|
||||
'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea; Path=/; Max-Age=604800'
|
||||
==
|
||||
~
|
||||
complete=%.y
|
||||
@ -2126,7 +2156,7 @@
|
||||
[%ipv4 .192.168.1.1]
|
||||
%'PUT'
|
||||
'/~/channel/0123456789abcdef'
|
||||
['cookie' 'urbauth=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
['cookie' 'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea']~
|
||||
::
|
||||
:- ~
|
||||
%- as-octs:mimes:html
|
||||
|
1949
pkg/interface/chat/package-lock.json
generated
1949
pkg/interface/chat/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ p, h1, h2, h3, h4, h5, h6, a, input, textarea, button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
textarea, select, input, button {
|
||||
textarea, input, button {
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
border: none;
|
||||
@ -144,4 +144,4 @@ h2 {
|
||||
|
||||
.label-small-mono.list-ship {
|
||||
line-height: 29px;
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,28 @@ class UrbitApi {
|
||||
setAuthTokens(authTokens) {
|
||||
this.authTokens = authTokens;
|
||||
this.bindPaths = [];
|
||||
|
||||
this.groups = {
|
||||
add: this.groupAdd.bind(this),
|
||||
remove: this.groupRemove.bind(this)
|
||||
};
|
||||
|
||||
this.chat = {
|
||||
message: this.chatMessage.bind(this),
|
||||
read: this.chatRead.bind(this)
|
||||
};
|
||||
|
||||
this.chatView = {
|
||||
create: this.chatViewCreate.bind(this),
|
||||
delete: this.chatViewDelete.bind(this),
|
||||
join: this.chatViewJoin.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
// keep default bind to hall, since its bind procedure more complex for now AA
|
||||
bind(path, method, ship = this.authTokens.ship, appl = "hall", success, fail) {
|
||||
bind(path, method, ship = this.authTokens.ship, app, success, fail, quit) {
|
||||
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
||||
|
||||
window.subscriptionId = window.urb.subscribe(ship, appl, path,
|
||||
window.subscriptionId = window.urb.subscribe(ship, app, path,
|
||||
(err) => {
|
||||
fail(err);
|
||||
},
|
||||
@ -28,35 +43,11 @@ class UrbitApi {
|
||||
}
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
fail(err);
|
||||
(qui) => {
|
||||
quit(qui);
|
||||
});
|
||||
}
|
||||
|
||||
hall(data) {
|
||||
this.action("hall", "json", data);
|
||||
}
|
||||
|
||||
addPendingMessage(data) {
|
||||
let pendingMap = store.state.pendingMessages;
|
||||
if (pendingMap.has(data.aud[0])) {
|
||||
pendingMap.get(data.aud[0]).push(data)
|
||||
} else {
|
||||
pendingMap.set(data.aud[0], [data])
|
||||
}
|
||||
store.setState({
|
||||
pendingMessages: pendingMap
|
||||
});
|
||||
}
|
||||
|
||||
chat(lis) {
|
||||
this.action("chat", "chat-action", {
|
||||
actions: {
|
||||
lis
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
action(appl, mark, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.urb.poke(ship, appl, mark, data,
|
||||
@ -69,90 +60,84 @@ class UrbitApi {
|
||||
});
|
||||
}
|
||||
|
||||
notify(aud, bool) {
|
||||
this.hall({
|
||||
notify: {
|
||||
aud,
|
||||
pes: !!bool ? 'hear' : 'gone'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
permit(cir, aud, message) {
|
||||
this.hall({
|
||||
permit: {
|
||||
nom: cir,
|
||||
sis: aud,
|
||||
inv: true
|
||||
}
|
||||
});
|
||||
|
||||
if (message) {
|
||||
this.invite(cir, aud);
|
||||
addPendingMessage(msg) {
|
||||
if (store.state.pendingMessages.has(msg.path)) {
|
||||
store.state.pendingMessages.get(msg.path).push(msg.envelope);
|
||||
} else {
|
||||
store.state.pendingMessages.set(msg.path, [msg.envelope]);
|
||||
}
|
||||
|
||||
store.setState({
|
||||
pendingMessages: store.state.pendingMessages
|
||||
});
|
||||
}
|
||||
|
||||
unpermit(cir, ship) {
|
||||
/*
|
||||
* lol, never send an unpermit to yourself.
|
||||
* it puts your ship into an infinite loop.
|
||||
* */
|
||||
if (ship === window.ship) {
|
||||
return;
|
||||
}
|
||||
this.hall({
|
||||
permit: {
|
||||
nom: cir,
|
||||
sis: [ship],
|
||||
inv: false
|
||||
groupsAction(data) {
|
||||
this.action("group-store", "group-action", data);
|
||||
}
|
||||
|
||||
groupAdd(members, path) {
|
||||
this.groupsAction({
|
||||
add: {
|
||||
members, path
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
invite(cir, aud) {
|
||||
let audInboxes = aud.map((aud) => `~${aud}/i`);
|
||||
let inviteMessage = {
|
||||
aud: audInboxes,
|
||||
ses: [{
|
||||
inv: {
|
||||
inv: true,
|
||||
cir: `~${window.ship}/${cir}`
|
||||
groupRemove(members, path) {
|
||||
this.groupsAction({
|
||||
remove: {
|
||||
members, path
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
chatAction(data) {
|
||||
this.action("chat-store", "json", data);
|
||||
}
|
||||
|
||||
chatMessage(path, author, when, letter) {
|
||||
let data = {
|
||||
message: {
|
||||
path,
|
||||
envelope: {
|
||||
uid: uuid(),
|
||||
number: 0,
|
||||
author,
|
||||
when,
|
||||
letter
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
this.hall({
|
||||
phrase: inviteMessage
|
||||
this.action("chat-hook", "json", data);
|
||||
this.addPendingMessage(data.message);
|
||||
}
|
||||
|
||||
chatRead(path, read) {
|
||||
this.chatAction({ read: { path } });
|
||||
}
|
||||
|
||||
chatViewAction(data) {
|
||||
this.action("chat-view", "json", data);
|
||||
}
|
||||
|
||||
chatViewCreate(path, security, read, write) {
|
||||
this.chatViewAction({
|
||||
create: {
|
||||
path, security, read, write
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
source(nom, sub) {
|
||||
this.hall({
|
||||
source: {
|
||||
nom: "inbox",
|
||||
sub: sub,
|
||||
srs: [nom]
|
||||
}
|
||||
})
|
||||
chatViewDelete(path) {
|
||||
this.chatViewAction({ delete: { path } });
|
||||
}
|
||||
|
||||
delete(nom) {
|
||||
this.hall({
|
||||
delete: {
|
||||
nom,
|
||||
why: ''
|
||||
}
|
||||
})
|
||||
chatViewJoin(ship, path) {
|
||||
this.chatViewAction({ join: { ship, path } });
|
||||
}
|
||||
|
||||
read(nom, red) {
|
||||
this.hall({
|
||||
read: {
|
||||
nom,
|
||||
red
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export let api = new UrbitApi();
|
||||
|
@ -5,6 +5,7 @@ import _ from 'lodash';
|
||||
import { Message } from '/components/lib/message';
|
||||
import { ChatTabBar } from '/components/lib/chat-tabbar';
|
||||
import { ChatInput } from '/components/lib/chat-input';
|
||||
import { deSig } from '/lib/util';
|
||||
|
||||
|
||||
export class ChatScreen extends Component {
|
||||
@ -12,16 +13,11 @@ export class ChatScreen extends Component {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
station: props.match.params.ship + "/" + props.match.params.station,
|
||||
circle: props.match.params.station,
|
||||
host: props.match.params.ship,
|
||||
numPeople: 0,
|
||||
station: `/${props.match.params.ship}/${props.match.params.station}`,
|
||||
numPages: 1,
|
||||
scrollLocked: false,
|
||||
};
|
||||
|
||||
this.pendingQueue = props.pendingMessages;
|
||||
|
||||
this.hasAskedForMessages = false;
|
||||
this.onScroll = this.onScroll.bind(this);
|
||||
|
||||
@ -32,7 +28,6 @@ export class ChatScreen extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateNumPeople();
|
||||
this.updateReadNumber();
|
||||
}
|
||||
|
||||
@ -46,22 +41,16 @@ export class ChatScreen extends Component {
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { props, state } = this;
|
||||
|
||||
if (prevProps.match.params.ship !== props.match.params.ship ||
|
||||
prevProps.match.params.station !== props.match.params.station
|
||||
) {
|
||||
console.log('switched circle');
|
||||
if ((prevProps.match.params.station !== props.match.params.station) ||
|
||||
(prevProps.match.params.ship !== props.match.params.ship)) {
|
||||
this.hasAskedForMessages = false;
|
||||
|
||||
clearInterval(this.updateReadInterval);
|
||||
|
||||
this.setState({
|
||||
station: props.match.params.ship + "/" + props.match.params.station,
|
||||
circle: props.match.params.station,
|
||||
host: props.match.params.ship,
|
||||
numPeople: 0,
|
||||
station: `/${props.match.params.ship}/${props.match.params.station}`,
|
||||
scrollLocked: false
|
||||
}, () => {
|
||||
this.updateNumPeople();
|
||||
this.scrollToBottom();
|
||||
this.updateReadInterval = setInterval(
|
||||
this.updateReadNumber.bind(this),
|
||||
@ -69,54 +58,40 @@ export class ChatScreen extends Component {
|
||||
);
|
||||
this.updateReadNumber();
|
||||
});
|
||||
} else if (!(state.station in props.configs)) {
|
||||
} else if (Object.keys(props.inbox).length === 0) {
|
||||
props.history.push('/~chat');
|
||||
} else if (props.envelopes.length - prevProps.envelopes.length >= 200) {
|
||||
this.hasAskedForMessages = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateReadNumber() {
|
||||
const { props, state } = this;
|
||||
|
||||
let internalCircle = 'hall-internal-' + state.circle;
|
||||
let internalStation = `~${window.ship}/${internalCircle}`;
|
||||
|
||||
let internalConfig = props.configs[internalStation] || false;
|
||||
let regularConfig = props.configs[state.station] || false;
|
||||
|
||||
let config = internalConfig || regularConfig;
|
||||
let messages = props.messages;
|
||||
|
||||
let lastMsgNum = (messages.length > 0) ?
|
||||
( messages[messages.length - 1].num + 1 ) : 0;
|
||||
|
||||
if (config && config.red < lastMsgNum) {
|
||||
if (internalConfig) {
|
||||
props.api.read(internalCircle, lastMsgNum);
|
||||
} else {
|
||||
props.api.read(state.circle, lastMsgNum);
|
||||
}
|
||||
if (props.read < props.envelopes.length) {
|
||||
props.api.chat.read(state.station);
|
||||
}
|
||||
}
|
||||
|
||||
askForMessages() {
|
||||
const { props, state } = this;
|
||||
let messages = props.messages;
|
||||
|
||||
if (state.numPages * 50 < props.messages.length - 200 ||
|
||||
if (state.numPages * 100 < props.envelopes.length - 400 ||
|
||||
this.hasAskedForMessages) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (messages.length > 0) {
|
||||
let end = messages[0].num;
|
||||
if (props.envelopes.length > 0) {
|
||||
let end = props.envelopes[0].number;
|
||||
if (end > 0) {
|
||||
let start = ((end - 400) > 0) ? end - 400 : 0;
|
||||
|
||||
if (start === 0 && end === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasAskedForMessages = true;
|
||||
|
||||
console.log('fetching new messages');
|
||||
|
||||
props.subscription.fetchMessages(state.station, start, end - 1);
|
||||
props.subscription.fetchMessages(start, end - 1, state.station);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,7 +115,7 @@ export class ChatScreen extends Component {
|
||||
});
|
||||
} else if (
|
||||
(e.target.scrollHeight - Math.round(e.target.scrollTop)) ===
|
||||
e.target.clientHeight
|
||||
(e.target.clientHeight)
|
||||
) {
|
||||
this.setState({
|
||||
numPages: 1,
|
||||
@ -155,8 +130,8 @@ export class ChatScreen extends Component {
|
||||
scrollLocked: false
|
||||
});
|
||||
} else if (
|
||||
(e.target.scrollHeight + Math.round(e.target.scrollTop)) ===
|
||||
e.target.clientHeight
|
||||
(e.target.scrollHeight + Math.round(e.target.scrollTop)) <=
|
||||
(e.target.clientHeight + 10)
|
||||
) {
|
||||
this.setState({
|
||||
numPages: this.state.numPages + 1,
|
||||
@ -170,104 +145,75 @@ export class ChatScreen extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
updateNumPeople() {
|
||||
let conf = this.props.configs[this.state.station] || {};
|
||||
let sis = _.get(conf, 'con.sis');
|
||||
let numPeople = !!sis ? sis.length : 0;
|
||||
if (numPeople !== this.state.numPeople) {
|
||||
this.setState({ numPeople });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
|
||||
let config = props.configs[state.station] || {};
|
||||
let messages = props.messages.slice(0);
|
||||
let messages = props.envelopes.slice(0);
|
||||
|
||||
// Pending messages get pinned to the bottom of the messages queue.
|
||||
|
||||
let pendingInRoom =
|
||||
(this.pendingQueue.has(this.state.station))
|
||||
? this.pendingQueue.get(this.state.station) : [];
|
||||
|
||||
pendingInRoom.map(function(value) {
|
||||
return value.pending = true;
|
||||
})
|
||||
|
||||
messages = messages.concat(pendingInRoom);
|
||||
|
||||
let lastMsgNum = (messages.length > 0) ?
|
||||
messages[messages.length - 1].num : 0;
|
||||
messages.length : 0;
|
||||
|
||||
if (messages.length > 50 * state.numPages) {
|
||||
if (messages.length > 100 * state.numPages) {
|
||||
messages = messages
|
||||
.slice(messages.length - (50 * state.numPages), messages.length);
|
||||
.slice(messages.length - (100 * state.numPages), messages.length);
|
||||
}
|
||||
|
||||
let reversedMessages = messages.reverse();
|
||||
let chatMessages = reversedMessages.map((msg, i) => {
|
||||
let pendingMessages =
|
||||
props.pendingMessages.has(state.station)
|
||||
? props.pendingMessages.get(state.station) : [];
|
||||
|
||||
pendingMessages.map(function(value) {
|
||||
return value.pending = true;
|
||||
})
|
||||
|
||||
let reversedMessages = messages.concat(pendingMessages);
|
||||
reversedMessages = reversedMessages.reverse();
|
||||
|
||||
reversedMessages = reversedMessages.map((msg, i) => {
|
||||
// Render sigil if previous message is not by the same sender
|
||||
let gamAut = ['gam', 'aut'];
|
||||
|
||||
// Local messages don't have a 'gam' prop, so look for the top level if it doesn't exist.
|
||||
let aut = msg.aut ? msg.aut : null;
|
||||
|
||||
// No gamAut? Return top level author for the same sender check.
|
||||
let aut = ['author'];
|
||||
let renderSigil =
|
||||
_.get(reversedMessages[i + 1], gamAut) !== _.get(msg, gamAut, aut);
|
||||
|
||||
// More padding top if previous message is not by the same sender
|
||||
_.get(reversedMessages[i + 1], aut) !== _.get(msg, aut, msg.author);
|
||||
let paddingTop = renderSigil;
|
||||
// More padding bot if next message is not by the same sender
|
||||
let paddingBot =
|
||||
_.get(reversedMessages[i - 1], gamAut) !== _.get(msg, gamAut, aut);
|
||||
|
||||
// Non-local ships don't have pending props.
|
||||
if (!msg.pending) {
|
||||
var pending = false;
|
||||
}
|
||||
|
||||
// Non-local ships don't have pending props.
|
||||
if (!pending) {
|
||||
var pending = false;
|
||||
}
|
||||
_.get(reversedMessages[i - 1], aut) !== _.get(msg, aut, msg.author);
|
||||
|
||||
return (
|
||||
<Message
|
||||
key={msg.gam ? msg.gam.uid : msg.uid}
|
||||
msg={msg.gam ? msg.gam : msg}
|
||||
key={msg.uid}
|
||||
msg={msg}
|
||||
renderSigil={renderSigil}
|
||||
paddingTop={paddingTop}
|
||||
paddingBot={paddingBot}
|
||||
pending={!!pending}/>
|
||||
paddingBot={paddingBot}
|
||||
pending={!!msg.pending} />
|
||||
);
|
||||
});
|
||||
|
||||
let peers = props.peers[state.station] || [window.ship];
|
||||
|
||||
let group = Array.from(props.group.values());
|
||||
|
||||
return (
|
||||
<div key={state.station}
|
||||
className="h-100 w-100 overflow-hidden flex flex-column">
|
||||
<div className='pl3 pt2 bb'>
|
||||
<h2>{state.circle}</h2>
|
||||
<h2>{state.station.substr(1)}</h2>
|
||||
<ChatTabBar {...props}
|
||||
station={state.station}
|
||||
numPeers={peers.length} />
|
||||
numPeers={group.length}
|
||||
isOwner={deSig(props.match.params.ship) === window.ship} />
|
||||
</div>
|
||||
<div
|
||||
className="overflow-y-scroll pt3 pb2 flex flex-column-reverse"
|
||||
style={{ height: 'calc(100% - 157px)', resize: 'vertical' }}
|
||||
onScroll={this.onScroll}>
|
||||
<div ref={ el => { this.scrollElement = el; }}></div>
|
||||
{chatMessages}
|
||||
{reversedMessages}
|
||||
</div>
|
||||
<ChatInput
|
||||
api={props.api}
|
||||
numMsgs={lastMsgNum}
|
||||
station={state.station}
|
||||
circle={state.circle}
|
||||
security={!!config ? config.con : {}}
|
||||
owner={deSig(props.match.params.ship)}
|
||||
permissions={props.permissions}
|
||||
placeholder='Message...' />
|
||||
</div>
|
||||
)
|
||||
|
108
pkg/interface/chat/src/js/components/join.js
Normal file
108
pkg/interface/chat/src/js/components/join.js
Normal file
@ -0,0 +1,108 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import urbitOb from 'urbit-ob';
|
||||
|
||||
|
||||
export class JoinScreen extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
station: '/',
|
||||
error: false
|
||||
};
|
||||
|
||||
this.stationChange = this.stationChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { props, state } = this;
|
||||
if (state.station in props.inbox) {
|
||||
props.history.push(`/~chat/room${state.station}`);
|
||||
}
|
||||
}
|
||||
|
||||
onClickJoin() {
|
||||
const { props, state } = this;
|
||||
|
||||
let text = state.station;
|
||||
if (text in props.inbox ||
|
||||
text.length === 0) {
|
||||
this.setState({
|
||||
error: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let station = text.split('/');
|
||||
let ship = station[0];
|
||||
station.splice(0, 1);
|
||||
station = '/' + station.join('/');
|
||||
|
||||
if (station.length < 2 || !urbitOb.isValidPatp(ship)) {
|
||||
this.setState({
|
||||
error: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
props.api.chatView.join(ship, station);
|
||||
this.props.history.push('/~chat');
|
||||
}
|
||||
|
||||
stationChange(event) {
|
||||
this.setState({
|
||||
station: event.target.value
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
let joinClasses = "db label-regular mt4 btn-font pointer underline bn";
|
||||
if (!this.state.station) {
|
||||
joinClasses = joinClasses + ' gray';
|
||||
}
|
||||
|
||||
let errElem = (<span />);
|
||||
if (this.state.error) {
|
||||
errElem = (
|
||||
<span className="body-small inter nice-red db">
|
||||
Chat must have a valid name.
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 pa3 pt2 overflow-x-hidden flex flex-column">
|
||||
<h2 className="mb3">Join</h2>
|
||||
<div className="w-50">
|
||||
<p className="body-medium mt3 db">Chatroom</p>
|
||||
<p className="body-small db mt2 mb3">
|
||||
Join an existing chatroom.
|
||||
Chatrooms follow the format ~shipname/chat-name.
|
||||
</p>
|
||||
<textarea
|
||||
ref={ e => { this.textarea = e; } }
|
||||
className="body-regular mono fw-normal ba pa2 mb2 db w-100"
|
||||
placeholder="~zod/chatroom"
|
||||
spellCheck="false"
|
||||
rows={1}
|
||||
style={{
|
||||
resize: 'none',
|
||||
}}
|
||||
onChange={this.stationChange} />
|
||||
{errElem}
|
||||
<br />
|
||||
<button
|
||||
onClick={this.onClickJoin.bind(this)}
|
||||
className={joinClasses}
|
||||
style={{ fontSize: '18px' }}
|
||||
>-> Join</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
|
||||
export class LandingScreen extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { props } = this;
|
||||
let station = props.match.params.ship + '/' + props.match.params.station;
|
||||
|
||||
if (station in props.configs) {
|
||||
props.history.push(`/~chat/${station}`);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { props } = this;
|
||||
let station = props.match.params.ship + '/' + props.match.params.station;
|
||||
|
||||
if (station in props.configs) {
|
||||
props.history.push(`/~chat/${station}`);
|
||||
}
|
||||
}
|
||||
|
||||
onClickSubscribe() {
|
||||
const { props } = this;
|
||||
|
||||
let station = props.match.params.ship + '/' + props.match.params.station;
|
||||
let actions = [
|
||||
{
|
||||
create: {
|
||||
nom: 'hall-internal-' + props.match.params.station,
|
||||
des: "chatroom",
|
||||
sec: "channel"
|
||||
}
|
||||
},
|
||||
{
|
||||
source: {
|
||||
nom: "inbox",
|
||||
sub: true,
|
||||
srs: [station]
|
||||
}
|
||||
},
|
||||
{
|
||||
source: {
|
||||
nom: "inbox",
|
||||
sub: true,
|
||||
srs: [`~${window.ship}/hall-internal-${props.match.params.station}`]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
this.props.api.chat(actions);
|
||||
this.props.history.push('/~chat');
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
let station = props.match.params.ship + '/' + props.match.params.station;
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 pt2 overflow-x-hidden flex flex-column">
|
||||
<div className='pl2 pt2 bb'>
|
||||
<h2>{station}</h2>
|
||||
</div>
|
||||
<div className="pa3 pl2">
|
||||
<h2 className="body-large">Not Yet Subscribed</h2>
|
||||
<p className="body-regular-400">
|
||||
You aren't subscribed to this chat yet.
|
||||
Subscribe to see its messages and members.
|
||||
</p>
|
||||
<br />
|
||||
<button
|
||||
onClick={this.onClickSubscribe.bind(this)}
|
||||
className="label-regular fw-bold pointer"
|
||||
>Subscribe</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -15,47 +15,8 @@ export class ChatInput extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
/*let closure = () => {
|
||||
let aud, sep;
|
||||
let wen = Date.now();
|
||||
let aut = window.ship;
|
||||
|
||||
aud = [props.station];
|
||||
sep = {
|
||||
lin: {
|
||||
msg: Date.now().toString(),
|
||||
pat: false
|
||||
}
|
||||
}
|
||||
|
||||
let uid;
|
||||
let message;
|
||||
|
||||
for (var i = 0; i < 40; i++) {
|
||||
uid = uuid();
|
||||
wen = Date.now();
|
||||
message = {
|
||||
uid,
|
||||
aut,
|
||||
wen,
|
||||
aud,
|
||||
sep,
|
||||
};
|
||||
|
||||
props.api.hall({
|
||||
convey: [message]
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(closure, 1000);
|
||||
};
|
||||
|
||||
setTimeout(closure, 2000);*/
|
||||
|
||||
this.state = {
|
||||
message: '',
|
||||
messageType: 'lin',
|
||||
clipboard: null
|
||||
};
|
||||
|
||||
this.textareaRef = React.createRef();
|
||||
@ -63,6 +24,22 @@ export class ChatInput extends Component {
|
||||
this.messageSubmit = this.messageSubmit.bind(this);
|
||||
this.messageChange = this.messageChange.bind(this);
|
||||
|
||||
// perf testing:
|
||||
/*let closure = () => {
|
||||
for (var i = 0; i < 30; i++) {
|
||||
props.api.chat.message(
|
||||
props.station,
|
||||
`~${window.ship}`,
|
||||
Date.now(),
|
||||
{
|
||||
text: `${Date.now()}`
|
||||
}
|
||||
);
|
||||
}
|
||||
setTimeout(closure, 1000);
|
||||
};
|
||||
setTimeout(closure, 2000);*/
|
||||
|
||||
moment.updateLocale('en', {
|
||||
relativeTime : {
|
||||
past: function(input) {
|
||||
@ -86,11 +63,7 @@ export class ChatInput extends Component {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.bindShortcuts();
|
||||
}
|
||||
|
||||
|
||||
bindShortcuts() {
|
||||
Mousetrap(this.textareaRef.current).bind('enter', e => {
|
||||
e.preventDefault();
|
||||
@ -101,45 +74,45 @@ export class ChatInput extends Component {
|
||||
}
|
||||
|
||||
messageChange(event) {
|
||||
const input = event.target.value;
|
||||
const previous = this.state.message;
|
||||
//NOTE dumb hack to work around paste event flow oddities
|
||||
const pasted = (previous.length === 0 && input.length > 1);
|
||||
if (input !== this.state.clipboard) {
|
||||
this.setState({
|
||||
message: input,
|
||||
messageType: this.getSpeechType(input),
|
||||
clipboard: (pasted ? input : null)
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
message: event.target.value
|
||||
});
|
||||
}
|
||||
|
||||
getSpeechType(input) {
|
||||
if (input[0] === '#') {
|
||||
return 'exp';
|
||||
} else if (input.indexOf('\n') >= 0) {
|
||||
return 'fat';
|
||||
} else if (input[0] === '@') {
|
||||
return 'lin@';
|
||||
} else if (this.isUrl(input)) {
|
||||
return 'url';
|
||||
getLetterType(letter) {
|
||||
if (letter[0] === '#') {
|
||||
letter = letter.slice(1);
|
||||
// remove insignificant leading whitespace.
|
||||
// aces might be relevant to style.
|
||||
while (letter[0] === '\n') {
|
||||
letter = letter.slice(1);
|
||||
}
|
||||
|
||||
return {
|
||||
code: {
|
||||
expression: letter,
|
||||
output: undefined
|
||||
}
|
||||
}
|
||||
} else if (letter[0] === '@') {
|
||||
letter = letter.slice(1);
|
||||
// remove insignificant leading whitespace.
|
||||
// aces might be relevant to style.
|
||||
while (letter[0] === '\n') {
|
||||
letter = letter.slice(1);
|
||||
}
|
||||
|
||||
return {
|
||||
me: letter
|
||||
}
|
||||
} else if (this.isUrl(letter)) {
|
||||
return {
|
||||
url: letter
|
||||
}
|
||||
} else {
|
||||
return 'lin';
|
||||
}
|
||||
}
|
||||
|
||||
getSpeechStyle(type, clipboard) {
|
||||
switch (type) {
|
||||
case 'lin@':
|
||||
return 'fs-italic';
|
||||
case 'url':
|
||||
return 'td-underline';
|
||||
case 'exp':
|
||||
return 'code';
|
||||
case 'fat':
|
||||
if (clipboard) return 'code';
|
||||
default:
|
||||
return '';
|
||||
return {
|
||||
text: letter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,93 +129,6 @@ export class ChatInput extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// turns select urls into arvo:// urls
|
||||
//
|
||||
// we detect app names from the url. if the app is known to handle requests
|
||||
// for remote data (instead of serving only from the host) we transfor the
|
||||
// url into a generic arvo:// one.
|
||||
// the app name format is pretty distinct and rare to find in the non-urbit
|
||||
// wild, but this could still result in false positives for older-school
|
||||
// websites serving pages under /~user paths.
|
||||
// we could match only on ship.arvo.network, but that would exclude those
|
||||
// running on localhost or under a custom domain.
|
||||
//
|
||||
//
|
||||
globalizeUrl(url) {
|
||||
const urlObject = new URL(url);
|
||||
const app = urlObject.pathname.split('/')[1];
|
||||
if (app === '~chat' ||
|
||||
app === '~publish') {
|
||||
//TODO send proper url speeches once hall starts using a url type that
|
||||
// supports non-http protocols.
|
||||
return { lin: {
|
||||
msg: 'arvo://' + url.slice(urlObject.origin.length),
|
||||
pat: false
|
||||
} };
|
||||
} else {
|
||||
return {url};
|
||||
}
|
||||
}
|
||||
|
||||
speechFromInput(content, type, clipboard) {
|
||||
switch (type) {
|
||||
case 'lin':
|
||||
return { lin: {
|
||||
msg: content,
|
||||
pat: false
|
||||
} };
|
||||
//
|
||||
case 'lin@':
|
||||
return { lin: {
|
||||
msg: content.slice(1),
|
||||
pat: true
|
||||
} };
|
||||
//
|
||||
case 'url':
|
||||
return this.globalizeUrl(content);
|
||||
//
|
||||
case 'exp':
|
||||
// remove leading #
|
||||
content = content.slice(1);
|
||||
// remove insignificant leading whitespace.
|
||||
// aces might be relevant to style.
|
||||
while (content[0] === '\n') {
|
||||
content = content.slice(1);
|
||||
}
|
||||
return { exp: {
|
||||
exp: content
|
||||
} };
|
||||
//
|
||||
case 'fat':
|
||||
// clipboard contents
|
||||
if (clipboard !== null) {
|
||||
return { fat: {
|
||||
sep: { lin: { msg: '', pat: false } },
|
||||
tac: { name: {
|
||||
nom: 'clipboard',
|
||||
tac: { text: content }
|
||||
} }
|
||||
} };
|
||||
// long-form message
|
||||
} else {
|
||||
const lines = content.split('\n');
|
||||
return { fat: {
|
||||
sep: { lin: {
|
||||
msg: lines[0],
|
||||
pat: false
|
||||
} },
|
||||
tac: { name: {
|
||||
nom: 'long-form',
|
||||
tac: { text: lines.slice(1).join('\n') }
|
||||
} },
|
||||
} };
|
||||
}
|
||||
//
|
||||
default:
|
||||
throw new Error('Unimplemented speech type', type);
|
||||
}
|
||||
}
|
||||
|
||||
messageSubmit() {
|
||||
const { props, state } = this;
|
||||
|
||||
@ -250,29 +136,17 @@ export class ChatInput extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
let message = {
|
||||
uid: uuid(),
|
||||
aut: window.ship,
|
||||
wen: Date.now(),
|
||||
aud: [props.station],
|
||||
sep: this.speechFromInput(
|
||||
state.message,
|
||||
state.messageType,
|
||||
state.clipboard
|
||||
)
|
||||
};
|
||||
let letter = this.getLetterType(state.message);
|
||||
|
||||
props.api.addPendingMessage(message);
|
||||
|
||||
props.api.hall(
|
||||
{
|
||||
convey: [message]
|
||||
}
|
||||
props.api.chat.message(
|
||||
props.station,
|
||||
`~${window.ship}`,
|
||||
Date.now(),
|
||||
letter
|
||||
);
|
||||
|
||||
this.setState({
|
||||
message: '',
|
||||
messageType: 'lin'
|
||||
});
|
||||
}
|
||||
|
||||
@ -293,14 +167,11 @@ export class ChatInput extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
writeAccessRender() {
|
||||
const { props, state } = this;
|
||||
|
||||
if (props.security && props.security.sec !== 'channel' &&
|
||||
!props.security.sis.includes(window.ship)) {
|
||||
return this.readOnlyRender();
|
||||
}
|
||||
|
||||
this.bindShortcuts();
|
||||
|
||||
return (
|
||||
<div className="pa3 cf flex black bt b--black-30" style={{ flexGrow: 1 }}>
|
||||
<div className="fl" style={{
|
||||
@ -312,9 +183,7 @@ export class ChatInput extends Component {
|
||||
</div>
|
||||
<div className="fr h-100 flex" style={{ flexGrow: 1 }}>
|
||||
<textarea
|
||||
className={'ml2 mt2 mr2 bn ' +
|
||||
this.getSpeechStyle(state.messageType, state.clipboard)
|
||||
}
|
||||
className={'ml2 mt2 mr2 bn'}
|
||||
style={{ flexGrow: 1, height: 40, paddingTop: 3, resize: 'none' }}
|
||||
ref={this.textareaRef}
|
||||
placeholder={props.placeholder}
|
||||
@ -329,4 +198,29 @@ export class ChatInput extends Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
|
||||
let writePermission = props.permissions[`/chat${props.station}/write`];
|
||||
if (writePermission) {
|
||||
if (writePermission.kind === 'black') {
|
||||
// black
|
||||
if (writePermission.who.has(window.ship)) {
|
||||
return this.readOnlyRender();
|
||||
} else {
|
||||
return this.writeAccessRender();
|
||||
}
|
||||
} else if (writePermission.kind === 'white') {
|
||||
// white
|
||||
if (writePermission.who.has(window.ship)) {
|
||||
return this.writeAccessRender();
|
||||
} else {
|
||||
return this.readOnlyRender();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return this.writeAccessRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import classnames from 'classnames';
|
||||
export class ChatTabBar extends Component {
|
||||
|
||||
render() {
|
||||
let toBaseLink = '/~chat/' + this.props.station;
|
||||
let props = this.props;
|
||||
|
||||
let bbStream = '',
|
||||
bbMembers = '',
|
||||
@ -16,12 +16,12 @@ export class ChatTabBar extends Component {
|
||||
memColor = '',
|
||||
setColor = '';
|
||||
|
||||
if (this.props.location.pathname.includes('/settings')) {
|
||||
if (props.location.pathname.includes('/settings')) {
|
||||
bbSettings = ' bb';
|
||||
strColor = 'gray';
|
||||
memColor = 'gray';
|
||||
setColor = 'black';
|
||||
} else if (this.props.location.pathname.includes('/members')) {
|
||||
} else if (props.location.pathname.includes('/members')) {
|
||||
bbMembers = ' bb';
|
||||
strColor = 'gray';
|
||||
memColor = 'black';
|
||||
@ -33,25 +33,28 @@ export class ChatTabBar extends Component {
|
||||
setColor = 'gray';
|
||||
}
|
||||
|
||||
let membersText = this.props.numPeers === 1
|
||||
? '1 Member' : `${this.props.numPeers} Members`;
|
||||
let membersText = props.numPeers === 1
|
||||
? '1 Member' : `${props.numPeers} Members`;
|
||||
|
||||
return (
|
||||
<div className="w-100" style={{ height:28 }}>
|
||||
<div className={"dib h-100" + bbStream} style={{width:'160px'}}>
|
||||
<Link
|
||||
className={'no-underline label-regular v-mid ' + strColor}
|
||||
to={toBaseLink}>Stream</Link>
|
||||
</div>
|
||||
<div className={"dib h-100" + bbMembers} style={{width:'160px'}}>
|
||||
<Link
|
||||
className={'no-underline label-regular v-mid ' + memColor}
|
||||
to={toBaseLink + '/members'}>{membersText}</Link>
|
||||
to={'/~chat/room' + props.station}>Stream</Link>
|
||||
</div>
|
||||
{ !!props.isOwner ? (
|
||||
<div className={"dib h-100" + bbMembers} style={{width:'160px'}}>
|
||||
<Link
|
||||
className={'no-underline label-regular v-mid ' + memColor}
|
||||
to={'/~chat/members' + props.station}>{membersText}</Link>
|
||||
</div>
|
||||
) : <div className="dib" style={{width:0}}></div>
|
||||
}
|
||||
<div className={"dib h-100" + bbSettings} style={{width:'160px'}}>
|
||||
<Link
|
||||
className={'no-underline label-regular v-mid ' + setColor}
|
||||
to={toBaseLink + '/settings'}>Settings</Link>
|
||||
to={'/~chat/settings' + props.station}>Settings</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
111
pkg/interface/chat/src/js/components/lib/invite-element.js
Normal file
111
pkg/interface/chat/src/js/components/lib/invite-element.js
Normal file
@ -0,0 +1,111 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { Sigil } from '/components/lib/icons/sigil';
|
||||
import { deSig } from '/lib/util';
|
||||
import urbitOb from 'urbit-ob';
|
||||
|
||||
|
||||
export class InviteElement extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
members: '',
|
||||
error: false,
|
||||
success: false
|
||||
};
|
||||
}
|
||||
|
||||
modifyMembers() {
|
||||
const { props, state } = this;
|
||||
|
||||
let aud = [];
|
||||
let isValid = true;
|
||||
if (state.members.length > 2) {
|
||||
aud = state.members
|
||||
.split(',')
|
||||
.map((mem) => `~${deSig(mem.trim())}`);
|
||||
|
||||
aud.forEach((mem) => {
|
||||
if (!urbitOb.isValidPatp(mem)) {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!isValid || (state.members.length > 0 && state.members.length < 3)) {
|
||||
this.setState({
|
||||
error: true,
|
||||
success: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.textarea) {
|
||||
this.textarea.value = '';
|
||||
}
|
||||
|
||||
this.setState({
|
||||
error: false,
|
||||
success: true,
|
||||
members: ''
|
||||
}, () => {
|
||||
props.api.groups.add(aud, props.path);
|
||||
});
|
||||
}
|
||||
|
||||
modifyMembersChange(e) {
|
||||
this.setState({
|
||||
members: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state} = this;
|
||||
let errorElem = !!state.error ? (
|
||||
<p className="pt2 nice-red label-regular">Invalid ship name.</p>
|
||||
) : (
|
||||
<div></div>
|
||||
);
|
||||
|
||||
let successElem = !!state.success ? (
|
||||
<p className="pt2 nice-green label-regular">Success!</p>
|
||||
) : (
|
||||
<div></div>
|
||||
);
|
||||
|
||||
let modifyButtonClasses = "label-regular black underline btn-font pointer";
|
||||
if (!state.error) {
|
||||
modifyButtonClasses = modifyButtonClasses + ' black';
|
||||
}
|
||||
|
||||
let buttonText = '';
|
||||
if (props.permissions.kind === 'black') {
|
||||
buttonText = '-> Ban';
|
||||
} else if (props.permissions.kind === 'white') {
|
||||
buttonText = '-> Invite';
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<textarea
|
||||
ref={ e => { this.textarea = e; } }
|
||||
className="w-90 db ba overflow-y-hidden mono gray mb2"
|
||||
style={{
|
||||
resize: 'none',
|
||||
height: 150
|
||||
}}
|
||||
spellCheck="false"
|
||||
onChange={this.modifyMembersChange.bind(this)}></textarea>
|
||||
<button
|
||||
onClick={this.modifyMembers.bind(this)}
|
||||
className={modifyButtonClasses}>
|
||||
{buttonText}
|
||||
</button>
|
||||
{errorElem}
|
||||
{successElem}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -7,24 +7,23 @@ export class MemberElement extends Component {
|
||||
|
||||
onRemove() {
|
||||
const { props } = this;
|
||||
props.api.unpermit(props.circle, props.ship);
|
||||
props.api.groups.remove([`~${props.ship}`], props.path);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
let actionElem;
|
||||
if (`~${props.ship}` === props.host) {
|
||||
if (props.ship === props.owner) {
|
||||
actionElem = (
|
||||
<p className="dib w-10 underline black label-small-mono label-regular">
|
||||
<p className="dib w-20 underline black label-small-mono label-regular">
|
||||
Host
|
||||
</p>
|
||||
);
|
||||
} else if (window.ship !== props.ship &&
|
||||
`~${window.ship}` === props.host) {
|
||||
} else if (window.ship !== props.ship && window.ship === props.owner) {
|
||||
actionElem = (
|
||||
<a onClick={this.onRemove.bind(this)}
|
||||
className="w-10 dib list-ship black underline label-small-mono pointer">
|
||||
className="w-20 dib list-ship black underline label-small-mono pointer">
|
||||
Remove
|
||||
</a>
|
||||
);
|
||||
@ -39,7 +38,7 @@ export class MemberElement extends Component {
|
||||
<Sigil ship={props.ship} size={32} />
|
||||
<p
|
||||
className={
|
||||
"w-80 dib v-mid black ml2 nowrap label-small-mono list-ship label-regular"
|
||||
"w-70 dib v-mid black ml2 nowrap label-small-mono list-ship label-regular"
|
||||
}>
|
||||
{props.ship}
|
||||
</p>
|
||||
|
@ -4,181 +4,61 @@ import classnames from 'classnames';
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class Message extends Component {
|
||||
|
||||
renderSpeech(speech) {
|
||||
if (_.has(speech, 'lin')) {
|
||||
return this.renderLin(speech.lin.msg, speech.lin.pat);
|
||||
} else if (_.has(speech, 'url')) {
|
||||
return this.renderUrl(speech.url);
|
||||
} else if (_.has(speech, 'exp')) {
|
||||
return this.renderExp(speech.exp.exp, speech.exp.res);
|
||||
} else if (_.has(speech, 'ire')) {
|
||||
return this.renderSpeech(speech.ire.sep);
|
||||
} else if (_.has(speech, 'app')) {
|
||||
return this.renderSpeech(speech.app.sep);
|
||||
} else if (_.has(speech, 'fat')) {
|
||||
return this.renderFat(speech.fat.sep, speech.fat.tac);
|
||||
} else {
|
||||
return this.renderUnknown();
|
||||
}
|
||||
}
|
||||
|
||||
renderUnknown() {
|
||||
return this.renderLin('<unknown message type>')
|
||||
}
|
||||
|
||||
renderLin(content, action = false) {
|
||||
if (content === '') {
|
||||
return null;
|
||||
}
|
||||
//TODO remove once arvo:// urls are supported in url speeches
|
||||
if (content.indexOf('arvo://') === 0) {
|
||||
return this.renderUrl(content);
|
||||
}
|
||||
return (
|
||||
<p className={`body-regular-400 v-top ${action ? 'fs-italic' : ''}`}>
|
||||
{content}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
renderUrl(url) {
|
||||
try {
|
||||
let urlObject = new URL(url);
|
||||
let imgMatch =
|
||||
/(jpg|img|png|gif|tiff|jpeg|JPG|IMG|PNG|TIFF|GIF|webp|WEBP|webm|WEBM)$/
|
||||
.exec(
|
||||
urlObject.pathname
|
||||
);
|
||||
if (imgMatch) {
|
||||
return this.renderImageUrl(url);
|
||||
} else {
|
||||
let localUrl = this.localizeUrl(url);
|
||||
return this.renderAnchor(localUrl, url);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('url render error', e);
|
||||
return this.renderAnchor(url);
|
||||
}
|
||||
}
|
||||
|
||||
renderImageUrl(url) {
|
||||
return this.renderAnchor(url, (
|
||||
<img
|
||||
src={url}
|
||||
style={{
|
||||
width:"50%",
|
||||
maxWidth: '250px'
|
||||
}}
|
||||
></img>
|
||||
));
|
||||
}
|
||||
|
||||
renderAnchor(href, content) {
|
||||
content = content || href;
|
||||
return (
|
||||
<a className="body-regular"
|
||||
href={href}
|
||||
target="_blank">{content}</a>
|
||||
);
|
||||
}
|
||||
|
||||
renderExp(expression, result) {
|
||||
return (<>
|
||||
<p>
|
||||
<pre className="clamp-attachment pa1 mt0 mb0 bg-light-gray">
|
||||
{expression}
|
||||
</pre>
|
||||
<pre className="clamp-attachment pa1 mt0 mb0">
|
||||
{result[0].join('\n')}
|
||||
</pre>
|
||||
</p>
|
||||
</>);
|
||||
}
|
||||
|
||||
renderFat(speech, attachment) {
|
||||
return (<>
|
||||
{this.renderSpeech(speech)}
|
||||
{this.renderAttachment(attachment)}
|
||||
</>);
|
||||
}
|
||||
|
||||
renderAttachment(content, title = '') {
|
||||
if (_.has(content, 'name')) {
|
||||
return this.renderAttachment(content.name.tac, content.name.nom);
|
||||
}
|
||||
|
||||
return (<details>
|
||||
<summary className="inter fs-italic">{'Attached: ' + title}</summary>
|
||||
{ _.has(content, 'text')
|
||||
? (title === 'long-form')
|
||||
? this.renderParagraphs(content.text.split('\n'))
|
||||
: this.renderPlaintext(content.text)
|
||||
: _.has(content, 'tank')
|
||||
? this.renderPlaintext(content.tank.join('\n'))
|
||||
: null
|
||||
}
|
||||
</details>);
|
||||
}
|
||||
|
||||
renderParagraphs(paragraphs) {
|
||||
return (<div className="clamp-attachment">
|
||||
{paragraphs.map(p => (<p className="mt2">{p}</p>))}
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderPlaintext(text) {
|
||||
return (<pre className="clamp-attachment">{text}</pre>);
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const { props } = this;
|
||||
let letter = props.msg.letter;
|
||||
|
||||
try {
|
||||
if (!_.has(props.msg, 'sep')) {
|
||||
return this.renderUnknown();
|
||||
}
|
||||
return this.renderSpeech(props.msg.sep);
|
||||
} catch (e) {
|
||||
console.error('speech rendering error', e);
|
||||
return this.renderUnknown();
|
||||
}
|
||||
}
|
||||
|
||||
renderAuthor() {
|
||||
const msg = this.props.msg;
|
||||
const ship = '~' + msg.aut;
|
||||
if (_.has(msg, 'sep.app.app')) {
|
||||
return `:${msg.sep.app.app} (${ship})`;
|
||||
if ('code' in letter) {
|
||||
let outputElement =
|
||||
(!!letter.code.output &&
|
||||
letter.code.output.length && letter.code.output.length > 0) ?
|
||||
(
|
||||
<pre className="clamp-attachment pa1 mt0 mb0">
|
||||
{letter.code.output[0].join('\n')}
|
||||
</pre>
|
||||
) : null;
|
||||
return (
|
||||
<span>
|
||||
<pre className="clamp-attachment pa1 mt0 mb0 bg-light-gray">
|
||||
{letter.code.expression}
|
||||
</pre>
|
||||
{outputElement}
|
||||
</span>
|
||||
);
|
||||
} else if ('url' in letter) {
|
||||
return (
|
||||
<a className="body-regular-400 v-top" href={letter.url}>
|
||||
{letter.url}
|
||||
</a>
|
||||
);
|
||||
} else if ('me' in letter) {
|
||||
return (
|
||||
<p className='body-regular-400 v-top'>
|
||||
{letter.me}
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
return ship;
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE see also lib/chat-input's globalizeUrl
|
||||
localizeUrl(url) {
|
||||
if (typeof url !== 'string') { throw 'Only localize strings!'; }
|
||||
const arvo = 'arvo://';
|
||||
if (url.indexOf(arvo) === 0) {
|
||||
// this application is being served by an urbit also, so /path will
|
||||
// point to the arvo url as hosted by this same urbit.
|
||||
return url.slice(arvo.length);
|
||||
} else {
|
||||
return url;
|
||||
return (
|
||||
<p className='body-regular-400 v-top'>
|
||||
{letter.text}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
let pending = !!props.msg.pending ? ' o-40' : '';
|
||||
let datestamp = moment.unix(props.msg.wen / 1000).format('LL');
|
||||
let datestamp = moment.unix(props.msg.when / 1000).format('LL');
|
||||
|
||||
let paddingTop = props.paddingTop ? 'pt3' : '';
|
||||
let paddingBot = props.paddingBot ? 'pb2' : 'pb1';
|
||||
|
||||
if (props.renderSigil) {
|
||||
let timestamp = moment.unix(props.msg.wen / 1000).format('hh:mm a');
|
||||
let timestamp = moment.unix(props.msg.when / 1000).format('hh:mm a');
|
||||
|
||||
return (
|
||||
<div className={"w-100 pl3 pr3 cf flex " + paddingTop + " " + paddingBot + pending}
|
||||
@ -186,12 +66,12 @@ export class Message extends Component {
|
||||
minHeight: 'min-content'
|
||||
}}>
|
||||
<div className="fl mr2">
|
||||
<Sigil ship={props.msg.aut} size={36} />
|
||||
<Sigil ship={props.msg.author} size={36} />
|
||||
</div>
|
||||
<div className="fr clamp-message" style={{ flexGrow: 1, marginTop: -8 }}>
|
||||
<div className="hide-child">
|
||||
<p className="v-top label-small-mono gray dib mr3">
|
||||
{this.renderAuthor()}
|
||||
{props.msg.author}
|
||||
</p>
|
||||
<p className="v-top label-small-mono gray dib">{timestamp}</p>
|
||||
<p className="v-top label-small-mono ml2 gray dib child">
|
||||
@ -203,7 +83,7 @@ export class Message extends Component {
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
let timestamp = moment.unix(props.msg.wen / 1000).format('hh:mm');
|
||||
let timestamp = moment.unix(props.msg.when / 1000).format('hh:mm');
|
||||
|
||||
return (
|
||||
<div className={"w-100 pr3 pb1 cf hide-child flex" + pending}
|
||||
|
@ -4,82 +4,6 @@ import _ from 'lodash';
|
||||
|
||||
export class SidebarInvite extends Component {
|
||||
|
||||
onAccept() {
|
||||
const { props } = this;
|
||||
let msg = props.msg;
|
||||
let cir = _.get(props, 'msg.sep.inv.cir', false);
|
||||
if (!cir) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateInvite(msg.uid, cir, true);
|
||||
}
|
||||
|
||||
onReject() {
|
||||
const { props } = this;
|
||||
let msg = props.msg;
|
||||
let cir = _.get(props, 'msg.sep.inv.cir', false);
|
||||
if (!cir) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateInvite(msg.uid, cir, false);
|
||||
}
|
||||
|
||||
updateInvite(uid, cir, resp) {
|
||||
let tagstring = resp ? "Accept" : "Reject";
|
||||
|
||||
let hostName = cir.split('/')[0];
|
||||
let circleName = cir.split('/')[1];
|
||||
|
||||
let actions = [
|
||||
{
|
||||
phrase: {
|
||||
aud: [`~${window.ship}/i`],
|
||||
ses: [{
|
||||
ire: {
|
||||
top: uid,
|
||||
sep: {
|
||||
lin: {
|
||||
msg: `${tagstring} ${cir}`,
|
||||
pat: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (resp && hostName !== `~${window.ship}`) {
|
||||
actions = actions.concat([
|
||||
{
|
||||
create: {
|
||||
nom: 'hall-internal-' + circleName,
|
||||
des: "chatroom",
|
||||
sec: "channel"
|
||||
}
|
||||
},
|
||||
{
|
||||
source: {
|
||||
nom: "inbox",
|
||||
sub: true,
|
||||
srs: [cir]
|
||||
}
|
||||
},
|
||||
{
|
||||
source: {
|
||||
nom: "inbox",
|
||||
sub: true,
|
||||
srs: [`~${window.ship}/hall-internal-${circleName}`]
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
this.props.api.chat(actions);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
|
@ -25,14 +25,26 @@ export class SidebarItem extends Component {
|
||||
}
|
||||
|
||||
getTimeSinceNewestMessage() {
|
||||
return !!this.props.wen ?
|
||||
moment.unix(this.props.wen / 1000).from(moment.utc())
|
||||
return !!this.props.when ?
|
||||
moment.unix(this.props.when / 1000).from(moment.utc())
|
||||
: '';
|
||||
}
|
||||
|
||||
onClick() {
|
||||
const { props } = this;
|
||||
props.history.push('/~chat/' + props.cir);
|
||||
props.history.push('/~chat/room' + props.box);
|
||||
}
|
||||
|
||||
getLetter(lett) {
|
||||
if ('text' in lett) {
|
||||
return lett.text;
|
||||
} else if ('url' in lett) {
|
||||
return lett.url;
|
||||
} else if ('code' in lett) {
|
||||
return lett.code.expression;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -47,18 +59,20 @@ export class SidebarItem extends Component {
|
||||
<div className="dib"></div>
|
||||
);
|
||||
|
||||
let description = this.getLetter(props.description);
|
||||
|
||||
let selectedCss = !!props.selected ? 'bg-light-gray' : 'bg-white pointer';
|
||||
return (
|
||||
<div className={'pa3 ' + selectedCss} onClick={this.onClick.bind(this)}>
|
||||
<div className='w-100 v-mid'>
|
||||
{unreadElem}
|
||||
<p className="dib body-regular lh-16">{props.title}</p>
|
||||
<p className="dib body-regular lh-16">{props.title.substr(1)}</p>
|
||||
</div>
|
||||
<div className="w-100">
|
||||
<p className='dib gray label-small-mono mr3 lh-16'>{props.ship}</p>
|
||||
<p className='dib gray label-small-mono lh-16'>{state.timeSinceNewestMessage}</p>
|
||||
</div>
|
||||
<p className='label-small gray clamp-3 lh-16 pt1'>{props.description}</p>
|
||||
<p className='label-small gray clamp-3 lh-16 pt1'>{description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -5,130 +5,117 @@ import urbitOb from 'urbit-ob';
|
||||
import { deSig } from '/lib/util';
|
||||
import { ChatTabBar } from '/components/lib/chat-tabbar';
|
||||
import { MemberElement } from '/components/lib/member-element';
|
||||
import { InviteElement } from '/components/lib/invite-element';
|
||||
|
||||
|
||||
export class MemberScreen extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
station: props.match.params.ship + "/" + props.match.params.station,
|
||||
circle: props.match.params.station,
|
||||
host: props.match.params.ship,
|
||||
invMembers: '',
|
||||
error: false,
|
||||
success: false
|
||||
station: `/${props.match.params.ship}/${props.match.params.station}`,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
inviteMembers() {
|
||||
const { props, state } = this;
|
||||
let sis = state.invMembers.split(',')
|
||||
.map((mem) => mem.trim())
|
||||
.map(deSig);
|
||||
|
||||
let isValid = true;
|
||||
sis.forEach((mem) => {
|
||||
if (!urbitOb.isValidPatp(`~${mem}`)) {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
props.api.permit(state.circle, sis, true);
|
||||
if (this.textarea) {
|
||||
this.textarea.value = '';
|
||||
}
|
||||
this.setState({
|
||||
error: false,
|
||||
success: true,
|
||||
invMembers: ''
|
||||
});
|
||||
} else {
|
||||
this.setState({ error: true, success: false });
|
||||
}
|
||||
}
|
||||
|
||||
inviteMembersChange(e) {
|
||||
this.setState({
|
||||
invMembers: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
|
||||
let peers = props.peers[state.station] || [window.ship];
|
||||
let listMembers = peers.map((mem) => {
|
||||
let writeGroup = Array.from(props.write.who.values());
|
||||
let readGroup = Array.from(props.read.who.values());
|
||||
|
||||
let writeText = '';
|
||||
let readText = '';
|
||||
let modWriteText = '';
|
||||
let modReadText = '';
|
||||
|
||||
if (props.write.kind === 'black') {
|
||||
writeText = 'Everyone banned from writing to this chat.';
|
||||
modWriteText = 'Ban someone from writing to this chat.';
|
||||
} else if (props.write.kind === 'white') {
|
||||
writeText = 'Everyone with permission to message this chat.';
|
||||
modWriteText = 'Invite someone to write to this chat.';
|
||||
}
|
||||
|
||||
if (props.read.kind === 'black') {
|
||||
readText = 'Everyone banned from reading this chat.';
|
||||
modReadText = 'Ban someone from reading this chat.';
|
||||
} else if (props.read.kind === 'white') {
|
||||
readText = 'Everyone with permission to read this chat.';
|
||||
modReadText = 'Invite someone to read this chat.';
|
||||
}
|
||||
|
||||
let writeListMembers = writeGroup.map((mem) => {
|
||||
return (
|
||||
<MemberElement
|
||||
key={mem}
|
||||
host={state.host}
|
||||
owner={deSig(props.match.params.ship)}
|
||||
ship={mem}
|
||||
circle={state.circle}
|
||||
path={`/chat${state.station}/write`}
|
||||
kind={props.write.kind}
|
||||
api={props.api} />
|
||||
);
|
||||
});
|
||||
|
||||
let readListMembers = readGroup.map((mem) => {
|
||||
return (
|
||||
<MemberElement
|
||||
key={mem}
|
||||
owner={deSig(props.match.params.ship)}
|
||||
ship={mem}
|
||||
path={`/chat${state.station}/read`}
|
||||
kind={props.read.kind}
|
||||
api={props.api} />
|
||||
);
|
||||
});
|
||||
|
||||
let errorElem = !!this.state.error ? (
|
||||
<p className="pa2 nice-red label-regular">Invalid ship name.</p>
|
||||
) : (
|
||||
<div></div>
|
||||
);
|
||||
|
||||
let successElem = !!this.state.success ? (
|
||||
<p className="pa2 nice-green label-regular">Sent invites!</p>
|
||||
) : (
|
||||
<div></div>
|
||||
);
|
||||
|
||||
|
||||
let inviteButtonClasses = "label-regular black underline btn-font pointer";
|
||||
if (!this.state.error) {
|
||||
inviteButtonClasses = inviteButtonClasses + ' black';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column">
|
||||
<div className='pl3 pt2 bb mb3'>
|
||||
<h2>{state.circle}</h2>
|
||||
<h2>{state.station.substr(1)}</h2>
|
||||
<ChatTabBar
|
||||
{...props}
|
||||
station={state.station}
|
||||
numPeers={peers.length} />
|
||||
numPeers={writeGroup.length}
|
||||
isOwner={deSig(props.match.params.ship) === window.ship} />
|
||||
</div>
|
||||
<div className="w-100 cf">
|
||||
<div className="w-50 fl pa2">
|
||||
<p className="body-regular">Permitted Members</p>
|
||||
<p className="label-regular gray mb3">
|
||||
Everyone with permission to see this chat.
|
||||
</p>
|
||||
{listMembers}
|
||||
<div className="w-50 fl pa2 pr3">
|
||||
<p className="body-regular mb3">Members</p>
|
||||
<p className="label-regular gray mb3">{writeText}</p>
|
||||
{writeListMembers}
|
||||
</div>
|
||||
<div className="w-50 fr pa2 pl3">
|
||||
<p className="body-regular mb3">Modify Permissions</p>
|
||||
<p className="label-regular gray mb3">
|
||||
{modWriteText}
|
||||
</p>
|
||||
{ window.ship === deSig(props.match.params.ship) ? (
|
||||
<InviteElement
|
||||
path={`/chat${state.station}/write`}
|
||||
station={state.station}
|
||||
permissions={props.write}
|
||||
api={props.api} />
|
||||
) : null }
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-100 cf mt2">
|
||||
<div className="w-50 fl pa2 pr3">
|
||||
<p className="label-regular gray mb3">{readText}</p>
|
||||
{readListMembers}
|
||||
</div>
|
||||
<div className="w-50 fr pa2 pl3">
|
||||
<p className="label-regular gray mb3">
|
||||
{modReadText}
|
||||
</p>
|
||||
{ window.ship === deSig(props.match.params.ship) ?
|
||||
( <InviteElement
|
||||
path={`/chat${state.station}/read`}
|
||||
permissions={props.read}
|
||||
api={props.api}/>
|
||||
) : null
|
||||
}
|
||||
</div>
|
||||
{ `~${window.ship}` === state.host ? (
|
||||
<div className="w-50 fr pa2">
|
||||
<p className="body-regular">Invite</p>
|
||||
<p className="label-regular gray mb3">
|
||||
Invite new participants to this chat.
|
||||
</p>
|
||||
<textarea
|
||||
ref={ e => { this.textarea = e; } }
|
||||
className="w-80 db ba overflow-y-hidden mono gray mb2"
|
||||
style={{
|
||||
resize: 'none',
|
||||
height: 150
|
||||
}}
|
||||
spellCheck="false"
|
||||
onChange={this.inviteMembersChange.bind(this)}></textarea>
|
||||
<button
|
||||
onClick={this.inviteMembers.bind(this)}
|
||||
className={inviteButtonClasses}>
|
||||
-> Invite
|
||||
</button>
|
||||
{errorElem}
|
||||
{successElem}
|
||||
</div>
|
||||
) : null }
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -12,21 +12,23 @@ export class NewScreen extends Component {
|
||||
this.state = {
|
||||
idName: '',
|
||||
invites: '',
|
||||
security: 'village',
|
||||
idError: false,
|
||||
inviteError: false
|
||||
};
|
||||
|
||||
this.idChange = this.idChange.bind(this);
|
||||
this.invChange = this.invChange.bind(this);
|
||||
this.securityChange = this.securityChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { props, state } = this;
|
||||
|
||||
if (prevProps.circles !== props.circles) {
|
||||
let station = `~${window.ship}/${state.idName}`;
|
||||
if (props.circles.includes(station)) {
|
||||
props.history.push('/~chat/' + station);
|
||||
if (prevProps !== props) {
|
||||
let station = `/~${window.ship}/${state.idName}`;
|
||||
if (station in props.inbox) {
|
||||
props.history.push('/~chat/room' + station);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,6 +43,10 @@ export class NewScreen extends Component {
|
||||
this.setState({invites: event.target.value});
|
||||
}
|
||||
|
||||
securityChange(event) {
|
||||
this.setState({security: event.target.value});
|
||||
}
|
||||
|
||||
onClickCreate() {
|
||||
const { props, state } = this;
|
||||
if (!state.idName) {
|
||||
@ -51,91 +57,73 @@ export class NewScreen extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
let station = `~${window.ship}/${state.idName}`;
|
||||
let actions = [
|
||||
{
|
||||
create: {
|
||||
nom: state.idName,
|
||||
des: "chatroom",
|
||||
sec: "village"
|
||||
}
|
||||
},
|
||||
{
|
||||
source: {
|
||||
nom: 'inbox',
|
||||
sub: true,
|
||||
srs: [station]
|
||||
}
|
||||
}
|
||||
];
|
||||
let station = `/${state.idName}`;
|
||||
|
||||
if (station in props.inbox) {
|
||||
this.setState({
|
||||
inviteError: false,
|
||||
idError: true,
|
||||
success: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.invites.length > 0) {
|
||||
// TODO: send invites
|
||||
let aud = [];
|
||||
let isValid = true;
|
||||
if (state.invites.length > 2) {
|
||||
aud = state.invites.split(',')
|
||||
.map((mem) => `~${deSig(mem.trim())}`);
|
||||
|
||||
let aud = state.invites.split(',')
|
||||
.map((mem) => mem.trim())
|
||||
.map(deSig);
|
||||
|
||||
let isValid = true;
|
||||
aud.forEach((mem) => {
|
||||
if (!urbitOb.isValidPatp(`~${mem}`)) {
|
||||
if (!urbitOb.isValidPatp(mem)) {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
actions.push({
|
||||
permit: {
|
||||
nom: state.idName,
|
||||
sis: aud,
|
||||
inv: true
|
||||
}
|
||||
});
|
||||
|
||||
actions.push({
|
||||
phrase: {
|
||||
aud: aud.map((aud) => `~${aud}/i`),
|
||||
ses: [{
|
||||
inv: {
|
||||
inv: true,
|
||||
cir: station
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
if (this.textarea) {
|
||||
this.textarea.value = '';
|
||||
}
|
||||
|
||||
this.setState({
|
||||
inviteError: false,
|
||||
idError: false,
|
||||
success: true,
|
||||
invites: ''
|
||||
}, () => {
|
||||
props.setSpinner(true);
|
||||
props.api.chat(actions);
|
||||
});
|
||||
|
||||
} else {
|
||||
this.setState({
|
||||
inviteError: true,
|
||||
idError: false,
|
||||
success: false
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
error: false,
|
||||
success: true,
|
||||
invites: ''
|
||||
}, () => {
|
||||
props.setSpinner(true);
|
||||
props.api.chat(actions);
|
||||
});
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
this.setState({
|
||||
inviteError: true,
|
||||
idError: false,
|
||||
success: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.textarea) {
|
||||
this.textarea.value = '';
|
||||
}
|
||||
|
||||
// TODO: don't do this, it's shitty
|
||||
let writeAud;
|
||||
let readAud;
|
||||
|
||||
if (state.security === 'village') {
|
||||
aud.push(`~${window.ship}`);
|
||||
readAud = aud.slice(); // white list
|
||||
writeAud = aud.slice(); // white list
|
||||
} else if (state.security === 'channel') {
|
||||
readAud = []; // black list
|
||||
writeAud = []; // black list
|
||||
} else if (state.security === 'journal') {
|
||||
aud.push(`~${window.ship}`);
|
||||
readAud = []; // black list
|
||||
writeAud = aud.slice(); // white list
|
||||
} else if (state.security === 'mailbox') {
|
||||
aud.push(`~${window.ship}`);
|
||||
readAud = aud.slice(); // white list
|
||||
writeAud = []; // black list
|
||||
}
|
||||
|
||||
this.setState({
|
||||
error: false,
|
||||
success: true,
|
||||
invites: ''
|
||||
}, () => {
|
||||
props.setSpinner(true);
|
||||
props.api.chatView.create(station, state.security, readAud, writeAud);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -194,6 +182,14 @@ export class NewScreen extends Component {
|
||||
}}
|
||||
onChange={this.invChange} />
|
||||
{invErrElem}
|
||||
<select
|
||||
value={this.state.securityValue}
|
||||
onChange={this.securityChange}>
|
||||
<option value="village">Village</option>
|
||||
<option value="channel">Channel</option>
|
||||
<option value="journal">Journal</option>
|
||||
<option value="mailbox">Mailbox</option>
|
||||
</select>
|
||||
<button
|
||||
onClick={this.onClickCreate.bind(this)}
|
||||
className={createClasses}
|
||||
|
@ -12,7 +12,7 @@ import { ChatScreen } from '/components/chat';
|
||||
import { MemberScreen } from '/components/member';
|
||||
import { SettingsScreen } from '/components/settings';
|
||||
import { NewScreen } from '/components/new';
|
||||
import { LandingScreen } from '/components/landing';
|
||||
import { JoinScreen } from '/components/join';
|
||||
|
||||
|
||||
export class Root extends Component {
|
||||
@ -33,75 +33,27 @@ export class Root extends Component {
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
|
||||
let configs = !!state.configs ? state.configs : {};
|
||||
|
||||
let circles = Object.keys(configs).filter((conf) => {
|
||||
return configs[conf] !== undefined && conf.split('/')[1] !== 'i';
|
||||
});
|
||||
|
||||
let messages = _.get(state, 'messages', {});
|
||||
let messagePreviews = {};
|
||||
Object.keys(messages).forEach((stat) => {
|
||||
let arr = messages[stat];
|
||||
if (arr.length === 0) {
|
||||
let unreads = {};
|
||||
Object.keys(state.inbox).forEach((stat) => {
|
||||
let envelopes = state.inbox[stat].envelopes;
|
||||
|
||||
if (envelopes.length === 0) {
|
||||
messagePreviews[stat] = false;
|
||||
} else {
|
||||
messagePreviews[stat] = arr[arr.length - 1];
|
||||
messagePreviews[stat] = envelopes[envelopes.length - 1];
|
||||
}
|
||||
|
||||
unreads[stat] = envelopes.length > state.inbox[stat].config.read;
|
||||
});
|
||||
|
||||
let unreads = {};
|
||||
circles.forEach((cir) => {
|
||||
if (cir in messages) {
|
||||
if (messages[cir].length === 0) {
|
||||
unreads[cir] = false;
|
||||
} else {
|
||||
let host = `~${window.ship}`;
|
||||
let circle = cir.split('/')[1];
|
||||
let internalStation = host + '/hall-internal-' + circle;
|
||||
|
||||
if (internalStation in state.configs) {
|
||||
if (!!state.configs[internalStation]) {
|
||||
unreads[cir] =
|
||||
state.configs[internalStation].red <=
|
||||
messages[cir][messages[cir].length - 1].num;
|
||||
} else {
|
||||
unreads[cir] = false;
|
||||
}
|
||||
} else if (cir in state.configs) {
|
||||
if (!!state.configs[cir]) {
|
||||
unreads[cir] =
|
||||
state.configs[cir].red <=
|
||||
messages[cir][messages[cir].length - 1].num;
|
||||
} else {
|
||||
unreads[cir] = false;
|
||||
}
|
||||
} else {
|
||||
unreads[cir] = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreads[cir] = false;
|
||||
}
|
||||
});
|
||||
|
||||
let invites = _.get(state, 'messages', {});
|
||||
if (`~${window.ship}/i` in invites) {
|
||||
invites = invites[`~${window.ship}/i`];
|
||||
} else {
|
||||
invites = [];
|
||||
}
|
||||
|
||||
|
||||
let inviteConfig = false;
|
||||
if (`~${window.ship}/i` in configs) {
|
||||
inviteConfig = configs[`~${window.ship}/i`];
|
||||
}
|
||||
|
||||
const renderChannelSidebar = (props) => (
|
||||
<Sidebar
|
||||
circles={circles}
|
||||
inbox={state.inbox}
|
||||
messagePreviews={messagePreviews}
|
||||
invites={invites}
|
||||
invites={[]}
|
||||
unreads={unreads}
|
||||
api={api}
|
||||
inviteConfig={inviteConfig}
|
||||
@ -115,14 +67,13 @@ export class Root extends Component {
|
||||
<Route exact path="/~chat"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<Skeleton
|
||||
sidebar={renderChannelSidebar(props)}>
|
||||
<Skeleton sidebar={renderChannelSidebar(props)}>
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column">
|
||||
<div className="pl3 pr3 pt2 pb3">
|
||||
<h2>Home</h2>
|
||||
<p className="body-regular-400 pt3">
|
||||
Select a chat from the sidebar
|
||||
or <Link to="/~chat/new">create a new one</Link>.
|
||||
<Link to="/~chat/new">Create a new chat</Link> or
|
||||
<Link to="/~chat/join">join an existing one.</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -138,62 +89,85 @@ export class Root extends Component {
|
||||
<NewScreen
|
||||
setSpinner={this.setSpinner}
|
||||
api={api}
|
||||
circles={circles}
|
||||
inbox={state.inbox || {}}
|
||||
{...props}
|
||||
/>
|
||||
</Skeleton>
|
||||
);
|
||||
}} />
|
||||
<Route exact path="/~chat/join/:ship/:station"
|
||||
<Route exact path="/~chat/join"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<Skeleton
|
||||
sidebar={renderChannelSidebar(props)}>
|
||||
<LandingScreen
|
||||
<Skeleton sidebar={renderChannelSidebar(props)}>
|
||||
<JoinScreen
|
||||
api={api}
|
||||
configs={configs}
|
||||
inbox={state.inbox}
|
||||
{...props}
|
||||
/>
|
||||
</Skeleton>
|
||||
);
|
||||
}} />
|
||||
<Route exact path="/~chat/:ship/:station"
|
||||
<Route exact path="/~chat/room/:ship/:station+"
|
||||
render={ (props) => {
|
||||
let station =
|
||||
props.match.params.ship
|
||||
+ "/" +
|
||||
props.match.params.station;
|
||||
let messages = state.messages[station] || [];
|
||||
`/${props.match.params.ship}/${props.match.params.station}`;
|
||||
let mailbox = state.inbox[station] || {
|
||||
config: {
|
||||
read: -1,
|
||||
length: 0
|
||||
},
|
||||
envelopes: []
|
||||
};
|
||||
|
||||
let write = state.groups[`/chat${station}/write`] || new Set([]);
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
sidebar={renderChannelSidebar(props) }>
|
||||
<Skeleton sidebar={renderChannelSidebar(props) }>
|
||||
<ChatScreen
|
||||
api={api}
|
||||
configs={configs}
|
||||
messages={messages}
|
||||
pendingMessages={state.pendingMessages}
|
||||
peers={state.peers}
|
||||
subscription={subscription}
|
||||
read={mailbox.config.read}
|
||||
envelopes={mailbox.envelopes}
|
||||
inbox={state.inbox}
|
||||
group={write}
|
||||
permissions={state.permissions}
|
||||
pendingMessages={state.pendingMessages}
|
||||
{...props}
|
||||
/>
|
||||
</Skeleton>
|
||||
);
|
||||
}} />
|
||||
<Route exact path="/~chat/:ship/:station/members"
|
||||
<Route exact path="/~chat/members/:ship/:station+"
|
||||
render={ (props) => {
|
||||
let station =
|
||||
`/${props.match.params.ship}/${props.match.params.station}`;
|
||||
let read = state.permissions[`/chat${station}/read`] || {
|
||||
kind: '',
|
||||
who: new Set([])
|
||||
};
|
||||
let write = state.permissions[`/chat${station}/write`] || {
|
||||
kind: '',
|
||||
who: new Set([])
|
||||
};
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
sidebar={renderChannelSidebar(props) }>
|
||||
<Skeleton sidebar={renderChannelSidebar(props) }>
|
||||
<MemberScreen
|
||||
{...props}
|
||||
api={api}
|
||||
peers={state.peers}
|
||||
read={read}
|
||||
write={write}
|
||||
permissions={state.permissions}
|
||||
/>
|
||||
</Skeleton>
|
||||
);
|
||||
}} />
|
||||
<Route exact path="/~chat/:ship/:station/settings"
|
||||
<Route exact path="/~chat/settings/:ship/:station+"
|
||||
render={ (props) => {
|
||||
let station =
|
||||
`/${props.match.params.ship}/${props.match.params.station}`;
|
||||
let write = state.groups[`/chat${station}/write`] || new Set([]);
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
spinner={this.state.spinner}
|
||||
@ -202,8 +176,8 @@ export class Root extends Component {
|
||||
{...props}
|
||||
setSpinner={this.setSpinner}
|
||||
api={api}
|
||||
peers={state.peers}
|
||||
circles={state.circles}
|
||||
group={write}
|
||||
inbox={state.inbox}
|
||||
/>
|
||||
</Skeleton>
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { deSig } from '/lib/util';
|
||||
|
||||
import { ChatTabBar } from '/components/lib/chat-tabbar';
|
||||
|
||||
@ -9,9 +10,7 @@ export class SettingsScreen extends Component {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
station: props.match.params.ship + "/" + props.match.params.station,
|
||||
circle: props.match.params.station,
|
||||
host: props.match.params.ship,
|
||||
station: `/${props.match.params.ship}/${props.match.params.station}`,
|
||||
isLoading: false
|
||||
};
|
||||
|
||||
@ -20,10 +19,11 @@ export class SettingsScreen extends Component {
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { props, state } = this;
|
||||
if (!!state.isLoading && !props.circles.includes(state.station)) {
|
||||
if (!!state.isLoading && !(state.station in props.inbox)) {
|
||||
this.setState({
|
||||
isLoading: false
|
||||
}, () => {
|
||||
props.setSpinner(false);
|
||||
props.history.push('/~chat');
|
||||
});
|
||||
}
|
||||
@ -31,29 +31,10 @@ export class SettingsScreen extends Component {
|
||||
|
||||
deleteChat() {
|
||||
const { props, state } = this;
|
||||
if (state.host === `~${window.ship}`) {
|
||||
props.api.delete(state.circle);
|
||||
} else {
|
||||
let internalCircle = 'hall-internal-' + state.circle;
|
||||
|
||||
props.api.chat([
|
||||
{
|
||||
source: {
|
||||
nom: 'inbox',
|
||||
sub: false,
|
||||
srs: [state.station]
|
||||
}
|
||||
},
|
||||
{
|
||||
delete: {
|
||||
nom: internalCircle,
|
||||
why: ''
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
props.api.chatView.delete(state.station);
|
||||
props.setSpinner(true);
|
||||
|
||||
this.setState({
|
||||
isLoading: true
|
||||
});
|
||||
@ -61,11 +42,12 @@ export class SettingsScreen extends Component {
|
||||
|
||||
renderDelete() {
|
||||
const { props, state } = this;
|
||||
|
||||
let titleText = "Delete Chat";
|
||||
let descriptionText = "Permanently delete this chat.";
|
||||
let buttonText = "-> Delete";
|
||||
|
||||
if (state.host !== `~${window.ship}`) {
|
||||
if (deSig(props.match.params.ship) !== window.ship) {
|
||||
titleText = "Leave Chat"
|
||||
descriptionText = "You will no longer have access to this chat."
|
||||
buttonText = "-> Leave";
|
||||
@ -81,25 +63,25 @@ export class SettingsScreen extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
let peers = props.peers[state.station] || [window.ship];
|
||||
|
||||
let writeGroup = Array.from(props.group.values());
|
||||
|
||||
if (!!state.isLoading) {
|
||||
let text = "Deleting...";
|
||||
if (state.host === `~${window.ship}`) {
|
||||
if (deSig(props.match.params.ship) !== window.ship) {
|
||||
text = "Leaving...";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column">
|
||||
<div className='pl3 pt2 bb mb3'>
|
||||
<h2>{state.circle}</h2>
|
||||
<h2>{state.station.substr(1)}</h2>
|
||||
<ChatTabBar
|
||||
{...props}
|
||||
station={state.station}
|
||||
numPeers={peers.length} />
|
||||
numPeers={writeGroup.length} />
|
||||
</div>
|
||||
<div className="w-100 cf pa3">
|
||||
<h2>{text}</h2>
|
||||
@ -111,11 +93,12 @@ export class SettingsScreen extends Component {
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column">
|
||||
<div className='pl3 pt2 bb mb3'>
|
||||
<h2>{state.circle}</h2>
|
||||
<h2>{state.station.substr(1)}</h2>
|
||||
<ChatTabBar
|
||||
{...props}
|
||||
station={state.station}
|
||||
numPeers={peers.length} />
|
||||
numPeers={writeGroup.length}
|
||||
isOwner={deSig(props.match.params.ship) === window.ship} />
|
||||
</div>
|
||||
<div className="w-100 cf pa3">
|
||||
<h2>Settings</h2>
|
||||
|
@ -1,57 +1,13 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from "react-router-dom";
|
||||
import classnames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { SidebarItem } from '/components/lib/sidebar-item';
|
||||
import { SidebarInvite } from '/components/lib/sidebar-invite';
|
||||
|
||||
|
||||
export class Sidebar extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
invites: []
|
||||
};
|
||||
|
||||
this.setInvitesToReadInterval = setInterval(
|
||||
this.setInvitesToRead.bind(this),
|
||||
1000
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.filterInvites();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps !== this.props) {
|
||||
this.filterInvites();
|
||||
}
|
||||
}
|
||||
|
||||
filterInvites() {
|
||||
const { props } = this;
|
||||
let invites = [];
|
||||
|
||||
let filterInvites = {};
|
||||
props.invites.forEach((msg) => {
|
||||
let uid = _.get(msg, 'gam.sep.ire.top', false);
|
||||
if (!uid) {
|
||||
invites.push(msg.gam);
|
||||
} else {
|
||||
filterInvites[uid] = true;
|
||||
}
|
||||
});
|
||||
|
||||
invites = invites.filter((msg) => {
|
||||
return !(msg.uid in filterInvites);
|
||||
})
|
||||
|
||||
this.setState({ invites });
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.setInvitesToReadInterval) {
|
||||
clearInterval(this.setInvitesToReadInterval);
|
||||
@ -59,93 +15,46 @@ export class Sidebar extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
setInvitesToRead() {
|
||||
const { props, state } = this;
|
||||
|
||||
if (
|
||||
props.inviteConfig &&
|
||||
'red' in props.inviteConfig &&
|
||||
props.invites.length > 0
|
||||
) {
|
||||
let invNum = (props.invites[props.invites.length - 1].num + 1);
|
||||
|
||||
if (
|
||||
props.inviteConfig.red < invNum &&
|
||||
(invNum - props.inviteConfig.red) > state.invites.length
|
||||
) {
|
||||
props.api.read('i', invNum - state.invites.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClickNew() {
|
||||
this.props.history.push('/~chat/new');
|
||||
}
|
||||
|
||||
summarizeMessage(speech) {
|
||||
const fallback = '...';
|
||||
if (_.has(speech, 'lin')) {
|
||||
return speech.lin.msg;
|
||||
} else if (_.has(speech, 'url')) {
|
||||
return speech.url;
|
||||
} else if (_.has(speech, 'exp')) {
|
||||
return '# ' + speech.exp.exp;
|
||||
} else if (_.has(speech, 'ire')) {
|
||||
return this.summarizeMessage(speech.ire.sep);
|
||||
} else if (_.has(speech, 'app')) {
|
||||
return this.summarizeMessage(speech.app.sep);
|
||||
} else if (_.has(speech, 'fat')) {
|
||||
const msg = this.summarizeMessage(speech.fat.sep);
|
||||
if (msg !== '' && msg !== fallback) return msg;
|
||||
return 'Attachment' +
|
||||
(_.has(speech, 'fat.tac.name.nom')
|
||||
? ': ' + speech.fat.tac.name.nom
|
||||
: '');
|
||||
} else {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
let station = props.match.params.ship + '/' + props.match.params.station;
|
||||
let station = props.match.params.ship + props.match.params.station;
|
||||
|
||||
console.log(props.circles);
|
||||
let sidebarItems = props.circles
|
||||
.filter((cir) => {
|
||||
return !cir.includes('hall-internal-');
|
||||
})
|
||||
.map((cir) => {
|
||||
let msg = props.messagePreviews[cir];
|
||||
let content = _.has(msg, 'gam.sep')
|
||||
? this.summarizeMessage(msg.gam.sep)
|
||||
: 'No messages yet';
|
||||
let aut = !!msg ? msg.gam.aut : '';
|
||||
let wen = !!msg ? msg.gam.wen : 0;
|
||||
let sidebarItems = Object.keys(props.inbox)
|
||||
.map((box) => {
|
||||
let msg = props.messagePreviews[box];
|
||||
let letter = _.has(msg, 'letter')
|
||||
? msg.letter
|
||||
: {text: 'No messages yet'};
|
||||
let author = !!msg ? msg.author : '';
|
||||
let when = !!msg ? msg.when : 0;
|
||||
return {
|
||||
msg,
|
||||
wen,
|
||||
aut,
|
||||
content,
|
||||
cir,
|
||||
title: cir.split('/')[1],
|
||||
selected: station === cir
|
||||
when,
|
||||
author,
|
||||
letter,
|
||||
box,
|
||||
title: box,
|
||||
selected: station === box
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return b.wen - a.wen;
|
||||
})
|
||||
.map((obj) => {
|
||||
let unread = props.unreads[obj.cir];
|
||||
let unread = props.unreads[obj.box];
|
||||
|
||||
return (
|
||||
<SidebarItem
|
||||
key={obj.cir + '/' + obj.wen}
|
||||
key={obj.box + '/' + obj.when}
|
||||
title={obj.title}
|
||||
description={obj.content}
|
||||
cir={obj.cir}
|
||||
wen={obj.wen}
|
||||
ship={obj.aut}
|
||||
description={obj.letter}
|
||||
box={obj.box}
|
||||
when={obj.when}
|
||||
ship={obj.author}
|
||||
selected={obj.selected}
|
||||
unread={unread}
|
||||
history={props.history}
|
||||
@ -153,21 +62,10 @@ export class Sidebar extends Component {
|
||||
);
|
||||
});
|
||||
|
||||
let inviteItems = state.invites.map((inv) => {
|
||||
return (
|
||||
<SidebarInvite
|
||||
key={inv.uid}
|
||||
msg={inv}
|
||||
api={props.api}
|
||||
config={props.inviteConfig}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="h-100 w-100 overflow-x-hidden flex flex-column">
|
||||
<div className="pl3 pr3 pt2 pb3 cf bb b--black-30" style={{height: '88px'}}>
|
||||
<h2 className="dib w-50 gray">Chat</h2>
|
||||
<h2 className="dib w-50 gray"><Link to="/~chat">Chat</Link></h2>
|
||||
<a
|
||||
className="dib tr w-50 pointer plus-font"
|
||||
onClick={this.onClickNew.bind(this)}>+</a>
|
||||
@ -175,7 +73,6 @@ export class Sidebar extends Component {
|
||||
<div className="overflow-y-auto" style={{
|
||||
height: 'calc(100vh - 60px - 48px)'
|
||||
}}>
|
||||
{inviteItems}
|
||||
{sidebarItems}
|
||||
</div>
|
||||
</div>
|
||||
|
78
pkg/interface/chat/src/js/reducers/chat-update.js
Normal file
78
pkg/interface/chat/src/js/reducers/chat-update.js
Normal file
@ -0,0 +1,78 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class ChatUpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'chat-update', false);
|
||||
if (data) {
|
||||
this.pending(data, state);
|
||||
this.message(data, state);
|
||||
this.messages(data, state);
|
||||
this.read(data, state);
|
||||
this.create(data, state);
|
||||
this.delete(data, state);
|
||||
}
|
||||
}
|
||||
|
||||
message(json, state) {
|
||||
let data = _.get(json, 'message', false);
|
||||
if (data) {
|
||||
state.inbox[data.path].envelopes.push(data.envelope);
|
||||
}
|
||||
}
|
||||
|
||||
messages(json, state) {
|
||||
let data = _.get(json, 'messages', false);
|
||||
if (data) {
|
||||
console.log(data);
|
||||
state.inbox[data.path].envelopes =
|
||||
data.envelopes.concat(state.inbox[data.path].envelopes);
|
||||
}
|
||||
}
|
||||
|
||||
read(json, state) {
|
||||
let data = _.get(json, 'read', false);
|
||||
if (data) {
|
||||
state.inbox[data.path].config.read =
|
||||
state.inbox[data.path].envelopes.length;
|
||||
}
|
||||
}
|
||||
|
||||
create(json, state) {
|
||||
let data = _.get(json, 'create', false);
|
||||
if (data) {
|
||||
state.inbox[`/~${data.ship}${data.path}`] = {
|
||||
envelopes: [],
|
||||
config: {
|
||||
read:0,
|
||||
length: 0,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
delete(json, state) {
|
||||
let data = _.get(json, 'delete', false);
|
||||
if (data) {
|
||||
delete state.inbox[data.path];
|
||||
}
|
||||
}
|
||||
|
||||
pending(json, state) {
|
||||
let msg = _.get(json, 'message', false);
|
||||
if (!msg || !state.pendingMessages.has(msg.path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mailbox = state.pendingMessages.get(msg.path);
|
||||
|
||||
for (let pendingMsg of mailbox) {
|
||||
if (msg.envelope.uid === pendingMsg.uid) {
|
||||
let index = mailbox.indexOf(pendingMsg);
|
||||
state.pendingMessages.get(msg.path).splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class ConfigReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'chat', false);
|
||||
if (data) {
|
||||
state.inbox = data.inbox;
|
||||
state.configs = data.configs;
|
||||
state.circles = data.circles;
|
||||
state.peers = data.peers;
|
||||
state.messages = state.messages || {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
pkg/interface/chat/src/js/reducers/group-update.js
Normal file
65
pkg/interface/chat/src/js/reducers/group-update.js
Normal file
@ -0,0 +1,65 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class GroupUpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'group-update', false);
|
||||
if (data) {
|
||||
this.add(data, state);
|
||||
this.remove(data, state);
|
||||
this.bundle(data, state);
|
||||
this.unbundle(data, state);
|
||||
this.keys(data, state);
|
||||
this.path(data, state);
|
||||
}
|
||||
}
|
||||
|
||||
add(json, state) {
|
||||
let data = _.get(json, 'add', false);
|
||||
if (data) {
|
||||
for (let member of data.members) {
|
||||
state.groups[data.path].add(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove(json, state) {
|
||||
let data = _.get(json, 'remove', false);
|
||||
if (data) {
|
||||
for (let member of data.members) {
|
||||
state.groups[data.path].delete(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bundle(json, state) {
|
||||
|
||||
let data = _.get(json, 'bundle', false);
|
||||
if (data) {
|
||||
state.groups[data.path] = new Set();
|
||||
}
|
||||
}
|
||||
|
||||
unbundle(json, state) {
|
||||
let data = _.get(json, 'unbundle', false);
|
||||
if (data) {
|
||||
delete state.groups[data.path];
|
||||
}
|
||||
}
|
||||
|
||||
keys(json, state) {
|
||||
let data = _.get(json, 'keys', false);
|
||||
if (data) {
|
||||
state.groupKeys = new Set(data.keys);
|
||||
}
|
||||
}
|
||||
|
||||
path(json, state) {
|
||||
let data = _.get(json, 'path', false);
|
||||
if (data) {
|
||||
state.groups[data.path] = new Set([data.members]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,13 +3,31 @@ import _ from 'lodash';
|
||||
|
||||
export class InitialReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'initial', false);
|
||||
let data = _.get(json, 'chat-initial', false);
|
||||
if (data) {
|
||||
state.messages = data.messages;
|
||||
state.inbox = data.inbox;
|
||||
state.configs = data.configs;
|
||||
state.circles = data.circles;
|
||||
state.peers = data.peers;
|
||||
state.inbox = data;
|
||||
}
|
||||
|
||||
data = _.get(json, 'group-initial', false);
|
||||
if (data) {
|
||||
for (let group in data) {
|
||||
state.groups[group] = new Set(data[group]);
|
||||
}
|
||||
}
|
||||
|
||||
data = _.get(json, 'permission-initial', false);
|
||||
if (data) {
|
||||
for (let perm in data) {
|
||||
state.permissions[perm] = {
|
||||
who: new Set(data[perm].who),
|
||||
kind: data[perm].kind
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data = _.get(json, 'invite-initial', false);
|
||||
if (data) {
|
||||
state.invites = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
52
pkg/interface/chat/src/js/reducers/invite-update.js
Normal file
52
pkg/interface/chat/src/js/reducers/invite-update.js
Normal file
@ -0,0 +1,52 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class InviteUpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'invite-update', false);
|
||||
if (data) {
|
||||
this.create(data, state);
|
||||
this.delete(data, state);
|
||||
this.invite(data, state);
|
||||
this.accept(data, state);
|
||||
this.decline(data, state);
|
||||
}
|
||||
}
|
||||
|
||||
create(json, state) {
|
||||
let data = _.get(json, 'create', false);
|
||||
if (data) {
|
||||
state.invites[data.path] = {};
|
||||
}
|
||||
}
|
||||
|
||||
delete(json, state) {
|
||||
let data = _.get(json, 'delete', false);
|
||||
if (data) {
|
||||
delete state.invites[data.path];
|
||||
}
|
||||
}
|
||||
|
||||
invite(json, state) {
|
||||
let data = _.get(json, 'invite', false);
|
||||
if (data) {
|
||||
state.invites[data.path][data.uid] = data.invite;
|
||||
}
|
||||
}
|
||||
|
||||
accept(json, state) {
|
||||
let data = _.get(json, 'accept', false);
|
||||
if (data) {
|
||||
delete state.invites[data.path][data.uid];
|
||||
}
|
||||
}
|
||||
|
||||
decline(json, state) {
|
||||
let data = _.get(json, 'decline', false);
|
||||
if (data) {
|
||||
delete state.invites[data.path][data.uid];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
51
pkg/interface/chat/src/js/reducers/permission-update.js
Normal file
51
pkg/interface/chat/src/js/reducers/permission-update.js
Normal file
@ -0,0 +1,51 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class PermissionUpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'permission-update', false);
|
||||
if (data) {
|
||||
this.create(data, state);
|
||||
this.delete(data, state);
|
||||
this.add(data, state);
|
||||
this.remove(data, state);
|
||||
}
|
||||
}
|
||||
|
||||
create(json, state) {
|
||||
let data = _.get(json, 'create', false);
|
||||
if (data) {
|
||||
state.permissions[data.path] = {
|
||||
kind: data.kind,
|
||||
who: new Set(data.who)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
delete(json, state) {
|
||||
let data = _.get(json, 'delete', false);
|
||||
if (data) {
|
||||
delete state.permissions[data.path];
|
||||
}
|
||||
}
|
||||
|
||||
add(json, state) {
|
||||
let data = _.get(json, 'add', false);
|
||||
if (data) {
|
||||
for (let member of data.who) {
|
||||
state.permissions[data.path].who.add(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove(json, state) {
|
||||
let data = _.get(json, 'remove', false);
|
||||
if (data) {
|
||||
for (let member of data.who) {
|
||||
state.permissions[data.path].who.delete(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,101 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class UpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'update', false);
|
||||
if (data) {
|
||||
this.reduceInbox(_.get(data, 'inbox', false), state);
|
||||
this.reducePending(_.get(data, 'message', false), state);
|
||||
this.reduceMessage(_.get(data, 'message', false), state);
|
||||
this.reduceMessages(_.get(data, 'messages', false), state);
|
||||
this.reduceConfig(_.get(data, 'config', false), state);
|
||||
this.reduceCircles(_.get(data, 'circles', false), state);
|
||||
this.reducePeers(_.get(data, 'peers', false), state);
|
||||
this.reduceDelete(_.get(data, 'delete', false), state);
|
||||
}
|
||||
}
|
||||
|
||||
reduceInbox(inbox, state) {
|
||||
if (inbox) {
|
||||
state.inbox = inbox;
|
||||
}
|
||||
}
|
||||
|
||||
reduceMessage(message, state) {
|
||||
if (message && message.circle in state.messages) {
|
||||
state.messages[message.circle].push(message.envelope);
|
||||
} else {
|
||||
state.messages[message.circle] = [message.envelope];
|
||||
}
|
||||
}
|
||||
|
||||
reducePending(message, state) {
|
||||
if (message && (state.pendingMessages.has(message.envelope.gam.aud[0]))) {
|
||||
for (let pendingMessage of state.pendingMessages.get(message.envelope.gam.aud[0])) {
|
||||
|
||||
// Does the incoming message match a pending one?
|
||||
if (message.envelope.gam.uid === pendingMessage.uid) {
|
||||
|
||||
// Mutating the pendingMessages array.
|
||||
let pendingMessageMap = state.pendingMessages;
|
||||
let matchedMessage = pendingMessageMap.get(pendingMessage.aud[0]).indexOf(pendingMessage);
|
||||
pendingMessageMap.get(pendingMessage.aud[0]).splice(matchedMessage, 1);
|
||||
state.pendingMessages = pendingMessageMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reduceMessages(msgs, state) {
|
||||
if (msgs) {
|
||||
|
||||
let staMsgs = state.messages[msgs.circle];
|
||||
if (msgs.circle in state.messages) {
|
||||
console.log('new messages object: ', msgs);
|
||||
console.log('lowest num in store: ', staMsgs[0].num);
|
||||
console.log('highest num in store: ', staMsgs[staMsgs.length - 1].num);
|
||||
|
||||
if (staMsgs.length > 0 && staMsgs[0].num - 1 === msgs.end) {
|
||||
state.messages[msgs.circle] = msgs.envelopes.concat(staMsgs);
|
||||
} else if (staMsgs.length === 0) {
|
||||
state.messages[msgs.circle] = msgs.envelopes;
|
||||
} else {
|
||||
console.error('%messages has inconsistent indices');
|
||||
}
|
||||
|
||||
} else {
|
||||
state.messages[msgs.circle] = msgs.envelopes;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
reduceConfig(config, state) {
|
||||
if (config) {
|
||||
state.configs[config.circle] = config.config;
|
||||
}
|
||||
}
|
||||
|
||||
reduceCircles(circles, state) {
|
||||
if (circles) {
|
||||
state.circles = circles.circles;
|
||||
}
|
||||
}
|
||||
|
||||
reducePeers(peers, state) {
|
||||
if (peers) {
|
||||
state.peers[peers.circle] = peers.peers;
|
||||
}
|
||||
}
|
||||
|
||||
reduceDelete(del, state) {
|
||||
if (del) {
|
||||
delete state.configs[del.circle];
|
||||
delete state.messages[del.circle];
|
||||
delete state.peers[del.circle];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
import { InitialReducer } from '/reducers/initial';
|
||||
import { ConfigReducer } from '/reducers/config';
|
||||
import { UpdateReducer } from '/reducers/update';
|
||||
import { GroupUpdateReducer } from '/reducers/group-update';
|
||||
import { ChatUpdateReducer } from '/reducers/chat-update';
|
||||
import { InviteUpdateReducer } from '/reducers/invite-update';
|
||||
import { PermissionUpdateReducer } from '/reducers/permission-update';
|
||||
|
||||
|
||||
class Store {
|
||||
constructor() {
|
||||
this.state = {
|
||||
inbox: {},
|
||||
messages: {},
|
||||
configs: {},
|
||||
circles: [],
|
||||
peers: {},
|
||||
groups: {},
|
||||
permissions: {},
|
||||
invites: {},
|
||||
spinner: false,
|
||||
pendingMessages: new Map([])
|
||||
};
|
||||
|
||||
this.initialReducer = new InitialReducer();
|
||||
this.configReducer = new ConfigReducer();
|
||||
this.updateReducer = new UpdateReducer();
|
||||
this.groupUpdateReducer = new GroupUpdateReducer();
|
||||
this.permissionUpdateReducer = new PermissionUpdateReducer();
|
||||
this.chatUpdateReducer = new ChatUpdateReducer();
|
||||
this.inviteUpdateReducer = new InviteUpdateReducer();
|
||||
this.setState = () => {};
|
||||
}
|
||||
|
||||
@ -30,8 +33,10 @@ class Store {
|
||||
|
||||
console.log(json);
|
||||
this.initialReducer.reduce(json, this.state);
|
||||
this.configReducer.reduce(json, this.state);
|
||||
this.updateReducer.reduce(json, this.state);
|
||||
this.groupUpdateReducer.reduce(json, this.state);
|
||||
this.permissionUpdateReducer.reduce(json, this.state);
|
||||
this.chatUpdateReducer.reduce(json, this.state);
|
||||
this.inviteUpdateReducer.reduce(json, this.state);
|
||||
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
@ -14,19 +14,18 @@ export class Subscription {
|
||||
}
|
||||
|
||||
initializeChat() {
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat',
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat-view',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
|
||||
fetchMessages(circle, start, end) {
|
||||
fetch(`/~chat/scroll/${circle}/${start}/${end}`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
store.handleEvent({
|
||||
data: json
|
||||
});
|
||||
});
|
||||
this.handleError.bind(this),
|
||||
this.handleQuitAndResubscribe.bind(this));
|
||||
api.bind('/all', 'PUT', api.authTokens.ship, 'group-store',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this),
|
||||
this.handleQuitAndResubscribe.bind(this));
|
||||
api.bind('/all', 'PUT', api.authTokens.ship, 'permission-store',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this),
|
||||
this.handleQuitAndResubscribe.bind(this));
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
@ -35,10 +34,27 @@ export class Subscription {
|
||||
|
||||
handleError(err) {
|
||||
console.error(err);
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
|
||||
handleQuitSilently(quit) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
handleQuitAndResubscribe(quit) {
|
||||
// TODO: resubscribe
|
||||
}
|
||||
|
||||
fetchMessages(start, end, path) {
|
||||
console.log(start, end, path);
|
||||
fetch(`/~chat/paginate/${start}/${end}${path}`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
store.handleEvent({
|
||||
data: json
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export let subscription = new Subscription();
|
||||
|
@ -7,40 +7,17 @@ export default class ChatTile extends Component {
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
let data = _.get(props.data, 'chat-configs', false);
|
||||
|
||||
let inviteNum = 0;
|
||||
let msgNum = 0;
|
||||
let inviteCircle = `~${window.ship}/i`;
|
||||
|
||||
let propNumbers = _.get(props, 'data.numbers.chat.numbers', false);
|
||||
let propConfigs = _.get(props, 'data.config.chat.configs', false);
|
||||
|
||||
if (propNumbers && propConfigs) {
|
||||
let numbers = {};
|
||||
|
||||
for (let i = 0; i < propNumbers.length; i++) {
|
||||
let num = propNumbers[i];
|
||||
numbers[num.circle] = num.length;
|
||||
}
|
||||
|
||||
let configs = Object.keys(propConfigs);
|
||||
|
||||
for (let i = 0; i < configs.length; i++) {
|
||||
let key = configs[i];
|
||||
let host = key.split('/')[0];
|
||||
|
||||
if (!propConfigs[key]) { break; }
|
||||
if (!(key in numbers)) { break; }
|
||||
|
||||
let red = propConfigs[key].red;
|
||||
|
||||
if (key === inviteCircle) {
|
||||
inviteNum = inviteNum - red + numbers[key];
|
||||
} else if (host === `~${window.ship}`) {
|
||||
msgNum = msgNum - red + numbers[key];
|
||||
} else {
|
||||
msgNum = msgNum + numbers[key];
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
Object.keys(data).forEach((conf) => {
|
||||
console.log(conf);
|
||||
msgNum = msgNum + data[conf].length - data[conf].read;
|
||||
});
|
||||
}
|
||||
|
||||
let invSuffix = (inviteNum === 1) ? (
|
||||
@ -106,4 +83,4 @@ export default class ChatTile extends Component {
|
||||
|
||||
}
|
||||
|
||||
window.chatTile = ChatTile;
|
||||
window['chat-viewTile'] = ChatTile;
|
||||
|
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 urbit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,10 +0,0 @@
|
||||
# Clock tile for Urbit
|
||||
|
||||
To install this on your Urbit planet:
|
||||
1. In your Urbit's Dojo, run |mount %
|
||||
2. Write in the filepath to your Urbit's pier in the urbitrc-sample file in this repository, then copy it to .urbitrc in this directory.
|
||||
3. Run `npm install` in terminal in this directory.
|
||||
4. Run `gulp default` in terminal in this directory.
|
||||
5. Run |start %clock in your Urbit's Dojo.
|
||||
|
||||
To see it, navigate to your Urbit's url and add /~home to the URL path.
|
1291
pkg/interface/clock/package-lock.json
generated
1291
pkg/interface/clock/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
URBIT_PIERS: [
|
||||
"/Users/logan/Dev/light-urbit/build/zod-chess-9/home",
|
||||
]
|
||||
};
|
253
pkg/interface/launch/package-lock.json
generated
253
pkg/interface/launch/package-lock.json
generated
@ -461,11 +461,6 @@
|
||||
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.11.8",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
|
||||
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
@ -1760,25 +1755,28 @@
|
||||
"dependencies": {
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1788,15 +1786,15 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@ -1804,37 +1802,40 @@
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1843,25 +1844,29 @@
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1870,13 +1875,15 @@
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1892,7 +1899,8 @@
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1906,13 +1914,15 @@
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1921,7 +1931,8 @@
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1930,7 +1941,8 @@
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1940,51 +1952,53 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
@ -1992,7 +2006,8 @@
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2001,22 +2016,24 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"needle": {
|
||||
"version": "2.3.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2027,7 +2044,8 @@
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.12.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2045,7 +2063,8 @@
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2055,13 +2074,15 @@
|
||||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.0.6",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2071,7 +2092,8 @@
|
||||
},
|
||||
"npmlog": {
|
||||
"version": "4.1.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2083,40 +2105,44 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2126,19 +2152,22 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.8",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2150,7 +2179,8 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
@ -2158,7 +2188,8 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2173,7 +2204,8 @@
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2182,45 +2214,50 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@ -2229,7 +2266,8 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2238,22 +2276,24 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2268,13 +2308,15 @@
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"bundled": true,
|
||||
"resolved": false,
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2283,15 +2325,15 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"resolved": false,
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -5659,15 +5701,6 @@
|
||||
"integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"urbit-ob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/urbit-ob/-/urbit-ob-3.2.0.tgz",
|
||||
"integrity": "sha512-nsDvWp4zILQ7VxnZnMtQgImMtgZiUbZTrs+bVh17VbXkYVmA+vxf3wEcgiEVsswGZKYAoG+7WQDLKd6t5Fcm5w==",
|
||||
"requires": {
|
||||
"bn.js": "^4.11.8",
|
||||
"lodash": "^4.17.11"
|
||||
}
|
||||
},
|
||||
"urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
|
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 urbit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,10 +0,0 @@
|
||||
# Weather tile for Urbit
|
||||
|
||||
To install this on your Urbit planet:
|
||||
1. In your Urbit's Dojo, run |mount %
|
||||
2. Write in the filepath to your Urbit's pier in the urbitrc-sample file in this repository, then copy it to .urbitrc in this directory.
|
||||
3. Run `npm install` in terminal in this directory.
|
||||
4. Run `gulp default` in terminal in this directory.
|
||||
5. Run |start %weather in your Urbit's Dojo.
|
||||
|
||||
To see it, navigate to your Urbit's url and add /~home to the URL path.
|
1011
pkg/interface/timer/package-lock.json
generated
1011
pkg/interface/timer/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -31,11 +31,7 @@
|
||||
"classnames": "^2.2.6",
|
||||
"lodash": "^4.17.11",
|
||||
"moment": "^2.20.1",
|
||||
"mousetrap": "^1.6.1",
|
||||
"react": "^16.5.2",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-router-dom": "^5.0.0"
|
||||
"react": "^16.5.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"natives": "1.1.3"
|
||||
|
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
URBIT_PIERS: [
|
||||
"/Users/logan/Dev/light-urbit/build/zod-chess-9/home",
|
||||
]
|
||||
};
|
2
pkg/urbit/.gitignore
vendored
2
pkg/urbit/.gitignore
vendored
@ -3,8 +3,6 @@
|
||||
#
|
||||
/config.mk
|
||||
include/config.h
|
||||
include/ca-bundle.h
|
||||
include/ivory.h
|
||||
#
|
||||
# Build Outputs
|
||||
#
|
||||
|
2
pkg/urbit/configure
vendored
2
pkg/urbit/configure
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
URBIT_VERSION=0.8.2
|
||||
URBIT_VERSION="0.9.0.rc-4"
|
||||
|
||||
deps=" \
|
||||
curl gmp sigsegv argon2 ed25519 ent h2o scrypt sni uv murmur3 secp256k1 \
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <ncurses/term.h>
|
||||
#include <dirent.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <h2o.h>
|
||||
#include <curl/curl.h>
|
||||
#include <argon2.h>
|
||||
@ -71,8 +70,6 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
c3_w arg_w;
|
||||
|
||||
u3_Host.ops_u.abo = c3n;
|
||||
u3_Host.ops_u.bat = c3n;
|
||||
u3_Host.ops_u.can = c3n;
|
||||
u3_Host.ops_u.dem = c3n;
|
||||
u3_Host.ops_u.dry = c3n;
|
||||
u3_Host.ops_u.gab = c3n;
|
||||
@ -89,13 +86,14 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
u3_Host.ops_u.pro = c3n;
|
||||
u3_Host.ops_u.qui = c3n;
|
||||
u3_Host.ops_u.rep = c3n;
|
||||
u3_Host.ops_u.tem = c3n;
|
||||
u3_Host.ops_u.tex = c3n;
|
||||
u3_Host.ops_u.tra = c3n;
|
||||
u3_Host.ops_u.veb = c3n;
|
||||
u3_Host.ops_u.kno_w = DefaultKernel;
|
||||
|
||||
while ( -1 != (ch_i=getopt(argc, argv,
|
||||
"G:J:B:K:A:H:I:w:u:e:E:f:F:k:p:LljabcCdgqsvxPDRS")) )
|
||||
"G:J:B:K:A:H:I:w:u:e:F:k:p:LljacdgqstvxPDRS")) )
|
||||
{
|
||||
switch ( ch_i ) {
|
||||
case 'J': {
|
||||
@ -126,10 +124,6 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
u3_Host.ops_u.eth_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'E': {
|
||||
u3_Host.ops_u.ets_c = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
case 'F': {
|
||||
u3_Host.ops_u.fak_c = _main_presig(optarg);
|
||||
u3_Host.ops_u.net = c3n;
|
||||
@ -148,12 +142,6 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
u3_Host.ops_u.tex = c3y;
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
if ( c3n == _main_readw(optarg, 100, &u3_Host.ops_u.fuz_w) ) {
|
||||
return c3n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'K': {
|
||||
if ( c3n == _main_readw(optarg, 256, &u3_Host.ops_u.kno_w) ) {
|
||||
return c3n;
|
||||
@ -178,9 +166,7 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
case 'l': { u3_Host.ops_u.lit = c3y; break; }
|
||||
case 'j': { u3_Host.ops_u.tra = c3y; break; }
|
||||
case 'a': { u3_Host.ops_u.abo = c3y; break; }
|
||||
case 'b': { u3_Host.ops_u.bat = c3y; break; }
|
||||
case 'c': { u3_Host.ops_u.nuu = c3y; break; }
|
||||
case 'C': { u3_Host.ops_u.can = c3y; break; }
|
||||
case 'd': { u3_Host.ops_u.dem = c3y; break; }
|
||||
case 'g': { u3_Host.ops_u.gab = c3y; break; }
|
||||
case 'P': { u3_Host.ops_u.pro = c3y; break; }
|
||||
@ -189,6 +175,7 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
case 'v': { u3_Host.ops_u.veb = c3y; break; }
|
||||
case 's': { u3_Host.ops_u.git = c3y; break; }
|
||||
case 'S': { u3_Host.ops_u.has = c3y; break; }
|
||||
case 't': { u3_Host.ops_u.tem = c3y; break; }
|
||||
case '?': default: {
|
||||
return c3n;
|
||||
}
|
||||
@ -235,9 +222,10 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
u3_Host.dir_c = strdup(argv[optind]);
|
||||
}
|
||||
|
||||
if ( c3y == u3_Host.ops_u.bat ) {
|
||||
u3_Host.ops_u.dem = c3y;
|
||||
u3_Host.ops_u.nuu = c3y;
|
||||
// daemon mode (-d) implies disabling terminal assumptions (-t)
|
||||
//
|
||||
if ( c3y == u3_Host.ops_u.dem ) {
|
||||
u3_Host.ops_u.tem = c3y;
|
||||
}
|
||||
|
||||
// make -c optional, catch invalid boot of existing pier
|
||||
@ -254,6 +242,10 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
fprintf(stderr, "normal usage: %s %s\n", argv[0], u3_Host.dir_c);
|
||||
exit(1);
|
||||
}
|
||||
else if ( 0 != access(u3_Host.dir_c, W_OK) ) {
|
||||
fprintf(stderr, "urbit: write permissions are required for %s\n", u3_Host.dir_c);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
c3_t imp_t = ((0 != u3_Host.ops_u.who_c) &&
|
||||
@ -294,11 +286,6 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.can == c3y && u3_Host.ops_u.ets_c != 0 ) {
|
||||
fprintf(stderr, "-C and -E cannot be used together\n");
|
||||
return c3n;
|
||||
}
|
||||
|
||||
if ( u3_Host.ops_u.eth_c == 0 && imp_t ) {
|
||||
u3_Host.ops_u.eth_c = "http://eth-mainnet.urbit.org:8545";
|
||||
}
|
||||
@ -380,13 +367,11 @@ u3_ve_usage(c3_i argc, c3_c** argv)
|
||||
// XX find a way to re-enable
|
||||
// "-A dir Use dir for initial galaxy sync\n",
|
||||
"-B pill Bootstrap from this pill\n",
|
||||
"-b Batch create\n",
|
||||
"-c pier Create a new urbit in pier/\n",
|
||||
"-D Recompute from events\n",
|
||||
"-d Daemon mode\n",
|
||||
"-d Daemon mode; implies -t\n",
|
||||
"-e url Ethereum gateway\n",
|
||||
"-F ship Fake keys; also disables networking\n",
|
||||
"-f Fuzz testing\n",
|
||||
"-g Set GC flag\n",
|
||||
"-j file Create json trace file\n",
|
||||
"-K stage Start at Hoon kernel version stage\n",
|
||||
@ -399,6 +384,7 @@ u3_ve_usage(c3_i argc, c3_c** argv)
|
||||
"-S Disable battery hashing\n",
|
||||
// XX find a way to re-enable
|
||||
// "-s Pill URL from arvo git hash\n",
|
||||
"-t Disable terminal/tty assumptions\n",
|
||||
"-u url URL from which to download pill\n",
|
||||
"-v Verbose\n",
|
||||
"-w name Boot as ~name\n",
|
||||
@ -583,6 +569,14 @@ _fork_into_background_process()
|
||||
exit(WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
/* _stop_on_boot_completed_cb(): exit gracefully after boot is complete
|
||||
*/
|
||||
static void
|
||||
_stop_on_boot_completed_cb()
|
||||
{
|
||||
u3_pier_exit(u3_pier_stub());
|
||||
}
|
||||
|
||||
c3_i
|
||||
main(c3_i argc,
|
||||
c3_c** argv)
|
||||
@ -614,6 +608,10 @@ main(c3_i argc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( c3y == u3_Host.ops_u.tex ) {
|
||||
u3_Host.bot_f = _stop_on_boot_completed_cb;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ( 0 == getuid() ) {
|
||||
chroot(u3_Host.dir_c);
|
||||
@ -680,14 +678,10 @@ main(c3_i argc,
|
||||
u3K.certs_c = strdup("/tmp/urbit-ca-cert-XXXXXX");
|
||||
_setup_cert_store(u3K.certs_c);
|
||||
|
||||
if ( c3y == u3_Host.ops_u.dem && c3n == u3_Host.ops_u.bat ) {
|
||||
if ( c3y == u3_Host.ops_u.dem ) {
|
||||
printf("boot: running as daemon\n");
|
||||
}
|
||||
|
||||
// Seed prng. Don't panic -- just for fuzz testing.
|
||||
//
|
||||
srand(getpid());
|
||||
|
||||
// Instantiate process globals.
|
||||
{
|
||||
/* Boot the image and checkpoint. Set flags.
|
||||
@ -726,6 +720,8 @@ main(c3_i argc,
|
||||
}
|
||||
|
||||
/* Set dry-run flag.
|
||||
**
|
||||
** XX also exit immediately?
|
||||
*/
|
||||
if ( _(u3_Host.ops_u.dry) ) {
|
||||
u3C.wag_w |= u3o_dryrun;
|
||||
|
@ -543,15 +543,11 @@
|
||||
c3_c* arv_c; // -A, initial sync from
|
||||
c3_o abo; // -a, abort aggressively
|
||||
c3_c* pil_c; // -B, bootstrap from
|
||||
c3_o bat; // -b, batch create
|
||||
c3_o can; // -C, chain-only, no eth snapshot
|
||||
c3_o nuu; // -c, new pier
|
||||
c3_o dry; // -D, dry compute, no checkpoint
|
||||
c3_o dem; // -d, daemon
|
||||
c3_c* ets_c; // -E, eth snapshot
|
||||
c3_c* eth_c; // -e, ethereum node url
|
||||
c3_c* fak_c; // -F, fake ship
|
||||
c3_w fuz_w; // -f, fuzz testing
|
||||
c3_c* gen_c; // -G, czar generator
|
||||
c3_o gab; // -g, test garbage collection
|
||||
c3_c* dns_c; // -H, ames bootstrap domain
|
||||
@ -567,9 +563,9 @@
|
||||
c3_o qui; // -q, quiet
|
||||
c3_o rep; // -R, report build info
|
||||
c3_o has; // -S, Skip battery hashes
|
||||
c3_o tem; // -t, Disable terminal/tty assumptions
|
||||
c3_o git; // -s, pill url from arvo git hash
|
||||
c3_c* url_c; // -u, pill url
|
||||
c3_o vno; // -V, replay without reboots
|
||||
c3_o veb; // -v, verbose (inverse of -q)
|
||||
c3_c* who_c; // -w, begin with ticket
|
||||
c3_o tex; // -x, exit after loading
|
||||
|
@ -592,29 +592,13 @@ _ce_patch_compose(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* _ce_sync(): sync a file descriptor.
|
||||
*/
|
||||
static void
|
||||
_ce_sync(c3_i fid_i)
|
||||
{
|
||||
#if defined(U3_OS_linux)
|
||||
fdatasync(fid_i);
|
||||
#elif defined(U3_OS_osx)
|
||||
fcntl(fid_i, F_FULLFSYNC);
|
||||
#elif defined(U3_OS_bsd)
|
||||
fsync(fid_i);
|
||||
#else
|
||||
# error "port: datasync"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* _ce_patch_sync(): make sure patch is synced to disk.
|
||||
*/
|
||||
static void
|
||||
_ce_patch_sync(u3_ce_patch* pat_u)
|
||||
{
|
||||
_ce_sync(pat_u->ctl_i);
|
||||
_ce_sync(pat_u->mem_i);
|
||||
c3_sync(pat_u->ctl_i);
|
||||
c3_sync(pat_u->mem_i);
|
||||
}
|
||||
|
||||
/* _ce_image_sync(): make sure image is synced to disk.
|
||||
@ -622,7 +606,7 @@ _ce_patch_sync(u3_ce_patch* pat_u)
|
||||
static void
|
||||
_ce_image_sync(u3e_image* img_u)
|
||||
{
|
||||
_ce_sync(img_u->fid_i);
|
||||
c3_sync(img_u->fid_i);
|
||||
}
|
||||
|
||||
/* _ce_patch_apply(): apply patch to image.
|
||||
@ -840,6 +824,8 @@ u3e_live(c3_o nuu_o, c3_c* dir_c)
|
||||
u3P.nor_u.nam_c = "north";
|
||||
u3P.sou_u.nam_c = "south";
|
||||
|
||||
// XX review dryrun requirements, enable or remove
|
||||
//
|
||||
#if 0
|
||||
if ( u3C.wag_w & u3o_dryrun ) {
|
||||
return c3y;
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "all.h"
|
||||
|
||||
// XX stack-overflow recovery should be gated by -a
|
||||
//
|
||||
#undef NO_OVERFLOW
|
||||
|
||||
/* (u3_noun)setjmp(u3R->esc.buf): setjmp within road.
|
||||
@ -610,6 +612,8 @@ c3_w Exit;
|
||||
** [%2 trace]
|
||||
** [%3 code trace]
|
||||
** ==
|
||||
**
|
||||
** XX several of these abort() calls should be gated by -a
|
||||
*/
|
||||
c3_i
|
||||
u3m_bail(u3_noun how)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user