Pull in latest v0.8.0.rc changes

This commit is contained in:
Benjamin Summers 2019-07-16 15:59:39 -07:00
parent 4f698bce8f
commit 34de4f3ada
414 changed files with 104925 additions and 508 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2b7ee602f18661a07c88f2fbb2297f2d8e6fd329db0afc760ad334a845e73c9c
size 4601348
oid sha256:e534cb57dc8b2bee35004d843c7e0b2d028ba699e86d47a58efac4b065ce2f1b
size 6047224

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:847a5166d8d5106a0c909c914cc96ee6bcb47afef6ebdd6c05bebcd8b01ae87a
size 5859838
oid sha256:96b1f1ad730789b1d557aac66b847047c98341bcf436e1927f40f082a728d641
size 3816083

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cdf8ed31292285c9dda789a8ac313babb4d9ce98f19ace4a813d821a9861d685
size 7168503
oid sha256:e4a4f8f86b18de5e410caeb491eecf8cf4fe24fbaba03ad8183b55a13eee154a
size 9108350

View File

@ -20,7 +20,7 @@ let
vendor =
with deps;
[ argon2 ed25519 h2o murmur3 scrypt secp256k1 sni softfloat3 uv ent ];
[ argon2 ed25519 h2o murmur3 scrypt secp256k1 sni softfloat3 uv ent ge-additions ];
in

View File

@ -12,6 +12,7 @@ crossenv.make_derivation rec {
"--disable-shared"
"--disable-manual"
"--disable-ldap"
"--with-ssl=${openssl}"
];
src = crossenv.nixpkgs.fetchurl {

View File

@ -10,6 +10,13 @@ let
bootbrass = ../../bin/brass.pill;
bootsolid = ../../bin/solid.pill;
rawzod = import ./fakeship {
inherit pkgs tlon deps debug;
pill = bootsolid;
ship = "zod";
arvo = null;
};
zod = import ./fakeship {
inherit pkgs tlon deps arvo debug;
pill = bootsolid;
@ -33,7 +40,7 @@ rec {
solid = import ./solid {
inherit arvo pkgs tlon deps debug;
pier = zod;
pier = rawzod;
};
brass = import ./brass {

View File

@ -2,7 +2,12 @@ source $stdenv/setup
set -ex
$URBIT -d -F $SHIP -A "$ARVO" -B "$PILL" $out
if [ -z "$ARVO" ]
then
$URBIT -d -F $SHIP -B "$PILL" $out
else
$URBIT -d -F $SHIP -A "$ARVO" -B "$PILL" $out
fi
check () {
[ 3 -eq "$(herb $out -d 3)" ]

View File

@ -15,7 +15,29 @@ cleanup () {
trap cleanup EXIT
herb ./pier -P solid.pill -d '+solid, =dub &'
# update pill strategy to ensure correct staging
#
herb ./pier -p hood -d "+hood/mount /=home="
cp $ARVO/lib/pill.hoon ./pier/home/lib/
chmod -R u+rw ./pier/home/lib/
herb ./pier -p hood -d "+hood/commit %home"
herb ./pier -p hood -d "+hood/unmount %home"
# stage new desk for pill contents
#
herb ./pier -p hood -d '+hood/merge %stage our %home'
herb ./pier -p hood -d "+hood/mount /=stage="
rm -rf ./pier/stage
cp -r $ARVO ./pier/stage
chmod -R u+rw ./pier/stage
herb ./pier -p hood -d "+hood/commit %stage"
herb ./pier -p hood -d "+hood/unmount %stage"
herb ./pier -P solid.pill -d '+solid /=stage=/sys, =dub &'
mv solid.pill $out

View File

@ -20,6 +20,8 @@ shutdown () {
trap shutdown EXIT
herb ./ship -p hood -d '+hood/mass'
# Start the test app
herb ./ship -p hood -d '+hood/start %test'
@ -28,6 +30,8 @@ herb ./ship -d '~& ~ ~& %start-test-cores ~'
herb ./ship -p test -d ':- %cores /'
herb ./ship -d '~& %finish-test-cores ~'
herb ./ship -p hood -d '+hood/mass'
# Run the %renders tests
herb ./ship -d '~& ~ ~& %start-test-renders ~'
herb ./ship -p test -d ':- %renders /'
@ -37,6 +41,8 @@ herb ./ship -d '~& %finish-test-renders ~'
herb ./ship -d '+test, =seed `@uvI`(shaz %reproducible)' |
tee test-generator-output
herb ./ship -p hood -d '+hood/mass'
shutdown
# Collect output

View File

@ -4,13 +4,18 @@ let
deps = import ../deps { inherit pkgs; };
ent = import ./ent { inherit pkgs; };
arvo = import ./arvo { inherit pkgs; };
herb = import ../../pkg/herb { inherit pkgs; };
ent = import ./ent { inherit pkgs; };
arvo = import ./arvo { inherit pkgs; };
herb = import ../../pkg/herb { inherit pkgs; };
ge-additions = import ./ge-additions {
inherit pkgs;
inherit (deps) ed25519;
};
mkUrbit = { debug }:
import ./urbit {
inherit pkgs ent debug;
inherit pkgs ent debug ge-additions;
inherit (deps) argon2 murmur3 uv ed25519 sni scrypt softfloat3;
inherit (deps) secp256k1 h2o;
};
@ -20,4 +25,4 @@ let
in
{ inherit ent arvo herb urbit urbit-debug; }
{ inherit ent ge-additions arvo herb urbit urbit-debug; }

View File

@ -0,0 +1,7 @@
source $stdenv/setup
cp -r $src ./src
chmod -R u+w ./src
cd ./src
PREFIX=$out make install

View File

@ -0,0 +1,12 @@
{ env_name, env, deps }:
env.make_derivation rec {
name = "ge-additions";
builder = ./release.sh;
src = ../../../pkg/ge-additions;
cross_inputs = [ deps.ed25519 ];
CC = "${env.host}-gcc";
AR = "${env.host}-ar";
}

View File

@ -0,0 +1,9 @@
{ pkgs, ed25519 }:
pkgs.stdenv.mkDerivation rec {
name = "ge-additions";
builder = ./builder.sh;
src = ../../../pkg/ge-additions;
nativeBuildInputs = [ ed25519 ];
}

View File

@ -0,0 +1,13 @@
source $setup
cp -r $src ./src
chmod -R u+w ./src
cd ./src
for dep in $cross_inputs; do
export CFLAGS="${CFLAGS-} -I$dep/include"
export LDFLAGS="${LDFLAGS-} -L$dep/lib"
done
PREFIX=$out make install

View File

@ -11,5 +11,5 @@ make all -j8
make test
mkdir -p $out/bin
cp urbit $out/bin/$exename
cp urbit-worker $out/bin/$exename-worker
cp ./build/urbit $out/bin/$exename
cp ./build/urbit-worker $out/bin/$exename-worker

View File

@ -1,7 +1,7 @@
{
pkgs,
debug,
argon2, ed25519, ent, h2o, murmur3, scrypt, secp256k1, sni, softfloat3, uv
argon2, ed25519, ent, ge-additions, h2o, murmur3, scrypt, secp256k1, sni, softfloat3, uv
}:
let
@ -11,10 +11,10 @@ let
deps =
with pkgs;
[ curl gmp libsigsegv ncurses openssl zlib lmdb ];
[ curl gmp libsigsegv ncurses openssl zlib lmdb cacert xxd ];
vendor =
[ argon2 softfloat3 ed25519 ent h2o scrypt uv murmur3 secp256k1 sni ];
[ argon2 softfloat3 ed25519 ent ge-additions h2o scrypt uv murmur3 secp256k1 sni ];
in

View File

@ -1,6 +1,6 @@
{ env_name, env, deps }:
{ ent, name ? "urbit", debug ? false }:
{ ent, ge-additions, cacert, xxd, name ? "urbit", debug ? false }:
let
@ -10,7 +10,7 @@ let
vendor =
with deps;
[ argon2 softfloat3 ed25519 h2o scrypt uv murmur3 secp256k1 sni ];
[ argon2 softfloat3 ed25519 ge-additions h2o scrypt uv murmur3 secp256k1 sni ];
in
@ -21,10 +21,12 @@ env.make_derivation {
CPU_DEBUG = debug;
EVENT_TIME_DEBUG = false;
NCURSES = env.ncurses;
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
name = "${name}-${env_name}";
exename = name;
src = ../../../pkg/urbit;
cross_inputs = crossdeps ++ vendor ++ [ ent ];
builder = ./release.sh;
name = "${name}-${env_name}";
exename = name;
src = ../../../pkg/urbit;
native_inputs = [ xxd ];
cross_inputs = crossdeps ++ vendor ++ [ ent ];
builder = ./release.sh;
}

View File

@ -14,9 +14,9 @@ PKG_CONFIG=pkg-config-cross \
HOST=$host \
bash ./configure
make urbit urbit-worker -j8
make build/urbit build/urbit-worker -j8
mkdir -p $out/bin
cp -r $NCURSES/share/terminfo $out/bin/$exename-terminfo
cp urbit $out/bin/$exename
cp urbit-worker $out/bin/$exename-worker
cp ./build/urbit $out/bin/$exename
cp ./build/urbit-worker $out/bin/$exename-worker

View File

@ -9,7 +9,8 @@ in
import ./default.nix {
inherit pkgs;
debug = false;
inherit (tlon) ent;
inherit (tlon)
ent ge-additions;
inherit (deps)
argon2 ed25519 h2o murmur3 scrypt secp256k1 sni softfloat3 uv;
}

View File

@ -16,16 +16,21 @@ let
ent = env:
import ./pkgs/ent/cross.nix env;
ge-additions = env:
import ./pkgs/ge-additions/cross.nix env;
urbit = env:
import ./pkgs/urbit/release.nix env
{ ent = ent env; debug = false; name = "urbit"; };
{ ent = ent env; ge-additions = ge-additions env; cacert = nixpkgs.cacert;
xxd = nixpkgs.xxd; debug = false; name = "urbit"; };
builds-for-platform = plat:
plat.deps // {
inherit (plat.env) curl libgmp libsigsegv ncurses openssl zlib lmdb;
inherit (plat.env) cmake_toolchain;
ent = ent plat;
urbit = urbit plat;
ent = ent plat;
ge-additions = ge-additions plat;
urbit = urbit plat;
};
darwin_extra = {

@ -1 +0,0 @@
Subproject commit 23507c12fbe8ff42cb165e1ec5456b895bf6de5b

3
pkg/arvo/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/sec/**/*.atom
*.swp
*.swo

80
pkg/arvo/.travis.yml Normal file
View File

@ -0,0 +1,80 @@
language: node_js
node_js:
- 4
before_install:
# pwd: ~/urbit/arvo
- cd .travis/
- bash check-trailing-whitespace.sh
- cd ../../
# pwd: ~/urbit
# building vere directly in lieu of a working debian package script
- wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
- unzip ninja-linux.zip
- sudo mv ninja /usr/bin/
install:
# pwd: ~/urbit
- pip3 install --user -I meson==0.44.1
- git clone https://github.com/urbit/urbit
- cd ./urbit
# pwd: ~/urbit/urbit
- git checkout $(cat ../arvo/.travis/pin-vere-commit.txt)
- ./scripts/bootstrap
- ./scripts/build
- sudo ninja -C build install
- cd ../arvo
# pwd: ~/urbit/arvo
before_script:
- cd .travis
# pwd: ~/urbit/arvo/.travis
- npm install
- bash get-or-build-pill.sh
# https://github.com/travis-ci/travis-ci/issues/2570
script:
- ulimit -c unlimited -S
- npm run -s test; bash print-core-backtrace.sh $?
before_deploy: "[ -d piers ] || { mkdir piers && tar cvzSf piers/zod-$TRAVIS_COMMIT.tgz zod/; }"
addons:
apt:
packages:
- python3
- python3-pip
- libgmp3-dev
- libsigsegv-dev
- openssl
- libssl-dev
- libncurses5-dev
- gcc
- libcurl4-gnutls-dev
- unzip
- gdb
deploy:
- skip_cleanup: true
provider: gcs
access_key_id: GOOGTADOPP55X5ZTH3IKAXQW
secret_access_key:
secure: lALZvAW22oBMCXafvDOkqKDkdP0K8bGKlSb6uhh54z+2bJu49+5vrfxgA9YLcExGiz8uFttzNYhEoAQEjb96DPHAHvH2iJrwieKltrWM4hLkGuSHVSCBIIm+Qe4BVRSVJPQ1rtO1ausNr0XuzO6BVnKY7NCrz8la2XNjm5+miQdtrJUnrfy2JsM/c/Bkwjj3Tc4op9Ne+7Xzc9DI6LB97XiJx5PgeOx1WeZi9IKQ3IhPBHBzBpBrJ4lWxb4PFvDUqNzSk1wuMGy/sH73IFhGcz3CZRZYbeICDdwmHcUnkdPxG6+RLH+YLhSxx175R+HdaARRQvRANxvY9KNJ11NKmV3Rs9q7fZgWZbrptuB0CDMhfZ/Aiz9tgHGV0UVhYHb8n614fDIKzpXwIy5DPjCKpxPoZRVzABQcdzPTvxnZtZDbarsfdfq0vh9xXNPLGuFYZQnZ6iEpv17qp/2TbeCBSMKIxwIG3LQTwr0a4wKL1T/YIZm6oiN6NycHhMHaczQIRANKw9e7oqbgnXu/WnqHIxyTY2CCvzVOgipRmKKa7jz7CcSoP883XZ9o7WAOnfJY+T4ofpdkzHn1ElNXPjDPpX7CUkowNFH4DZk2Ljwe0CgxPOF6ygnsNrqqs4XoNQaBnHGXMq20Upg6OK9MBmZibtlX9STCeSAt4WudekpEOPU=
bucket: ci-piers.urbit.org
local-dir: piers/
acl: public-read
on:
repo: urbit/arvo
all_branches: true
- skip_cleanup: true
provider: gcs
access_key_id: GOOGTADOPP55X5ZTH3IKAXQW
secret_access_key:
secure: lALZvAW22oBMCXafvDOkqKDkdP0K8bGKlSb6uhh54z+2bJu49+5vrfxgA9YLcExGiz8uFttzNYhEoAQEjb96DPHAHvH2iJrwieKltrWM4hLkGuSHVSCBIIm+Qe4BVRSVJPQ1rtO1ausNr0XuzO6BVnKY7NCrz8la2XNjm5+miQdtrJUnrfy2JsM/c/Bkwjj3Tc4op9Ne+7Xzc9DI6LB97XiJx5PgeOx1WeZi9IKQ3IhPBHBzBpBrJ4lWxb4PFvDUqNzSk1wuMGy/sH73IFhGcz3CZRZYbeICDdwmHcUnkdPxG6+RLH+YLhSxx175R+HdaARRQvRANxvY9KNJ11NKmV3Rs9q7fZgWZbrptuB0CDMhfZ/Aiz9tgHGV0UVhYHb8n614fDIKzpXwIy5DPjCKpxPoZRVzABQcdzPTvxnZtZDbarsfdfq0vh9xXNPLGuFYZQnZ6iEpv17qp/2TbeCBSMKIxwIG3LQTwr0a4wKL1T/YIZm6oiN6NycHhMHaczQIRANKw9e7oqbgnXu/WnqHIxyTY2CCvzVOgipRmKKa7jz7CcSoP883XZ9o7WAOnfJY+T4ofpdkzHn1ElNXPjDPpX7CUkowNFH4DZk2Ljwe0CgxPOF6ygnsNrqqs4XoNQaBnHGXMq20Upg6OK9MBmZibtlX9STCeSAt4WudekpEOPU=
bucket: bootstrap.urbit.org
local-dir: built-pill/
acl: public-read
on:
condition: "-d built-pill/"
repo: urbit/arvo
all_branches: true

2
pkg/arvo/.travis/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Don't show in diffs or auto-merge
package-lock.json binary

1
pkg/arvo/.travis/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

View File

@ -0,0 +1,11 @@
#!/bin/bash
whitespace=$(find .. -path ../.git -prune -o \
-type f -exec egrep -l " +$" {} \;);
if [ ! -z $whitespace ]
then
echo 'found trailing whitespace in:';
echo $whitespace;
exit 1;
fi

View File

@ -0,0 +1,64 @@
#!/bin/bash
set -euo pipefail
set -x
# add urbit-runner to $PATH
PATH=./node_modules/.bin/:$PATH
# XX use -s instead of hash pill
HASH=$(git -C .. log -1 HEAD --format=%H -- sys/)
export PILL_NAME="git-${HASH:0:10}"
if [ ! ${PILL_FORCE:-} ]; then
: Trying pill for commit
wget https://bootstrap.urbit.org/$PILL_NAME.pill -O urbit.pill && exit 0
fi
# if wget failed
if [ ${TRAVIS_COMMIT:-} ] && [ $TRAVIS_COMMIT != $HASH ]; then
: Directory sys/ not modified in commit $TRAVIS_COMMIT
: FIXME ignoring, as current sys/ commits are unlikely to contain the pill-build code
:
# : For auto-build please tag and push $HASH
# exit 1
fi
mkdir prev
{
: Pilling: trying pinned fakezod
wget -i pin-parent-pill-pier.url -O - | tar xvz -C prev/ &&
: Downloaded prev/zod &&
urbit-runner -S prev/zod <<' .'
|autoload |
|mount %
.
[ $? = 0 ] && cp -r ../sys prev/zod/home/ &&
cp ../gen/solid.hoon prev/zod/home/gen/ &&
cp ../lib/pill.hoon prev/zod/home/lib/
} || {
: Pilling: Parent-pill pier not available, trying preceding pill commit
HASH2=$(git -C .. log -2 $HASH --format=%H -- sys/ | tail -1)
PILL_NAME2="git-${HASH2:0:10}"
wget https://bootstrap.urbit.org/$PILL_NAME2.pill -O prev/urbit.pill &&
([ -d prev/zod ] && rm -r prev/zod || true) &&
urbit-runner -A .. -B prev/urbit.pill -cSF zod prev/zod <<' .'
%booted-prev-zod
.
} || {
: Pilling: Out of ideas
exit 1
}
: Pier created, soliding actual pill
urbit-runner -S prev/zod <<.
|label %home %$PILL_NAME
.urbit/pill +solid /==/$PILL_NAME/sys, =dub &
.
cp prev/zod/.urb/put/urbit.pill urbit.pill
mkdir built-pill; cp urbit.pill built-pill/$PILL_NAME.pill
:
: Created $PILL_NAME.pill, to be uploaded if tests pass
:

753
pkg/arvo/.travis/package-lock.json generated Normal file
View File

@ -0,0 +1,753 @@
{
"name": "arvo-tests",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
}
},
"array-differ": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
"integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
},
"array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
"requires": {
"array-uniq": "^1.0.1"
}
},
"array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"bluebird": {
"version": "2.11.0",
"resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
"integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"colors": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz",
"integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ=="
},
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"del": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
"integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
"requires": {
"globby": "^5.0.0",
"is-path-cwd": "^1.0.0",
"is-path-in-cwd": "^1.0.0",
"object-assign": "^4.0.1",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"rimraf": "^2.2.8"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"emitter-mixin": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/emitter-mixin/-/emitter-mixin-0.0.3.tgz",
"integrity": "sha1-WUjLKG8uSO3DslGnz8H3iDOW1lw="
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
"requires": {
"prr": "~1.0.1"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"extend": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz",
"integrity": "sha1-oPX9bPyDpf5J72mNYOyKYk3UV2w="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"globby": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
"integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
"requires": {
"array-union": "^1.0.1",
"arrify": "^1.0.0",
"glob": "^7.0.3",
"object-assign": "^4.0.1",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"graceful-fs": {
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
"integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
"requires": {
"ajv": "^5.3.0",
"har-schema": "^2.0.0"
}
},
"hoek": {
"version": "4.2.1",
"resolved": "http://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"is-path-cwd": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
"integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0="
},
"is-path-in-cwd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
"integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
"requires": {
"is-path-inside": "^1.0.0"
}
},
"is-path-inside": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
"integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
"requires": {
"path-is-inside": "^1.0.1"
}
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"isemail": {
"version": "2.2.1",
"resolved": "http://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz",
"integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"items": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/items/-/items-2.1.1.tgz",
"integrity": "sha1-i9FtnIOxlSneWuoyGsqtp4NkoZg="
},
"joi": {
"version": "9.2.0",
"resolved": "http://registry.npmjs.org/joi/-/joi-9.2.0.tgz",
"integrity": "sha1-M4WseQGSEwy+Iw6ALsAskhW7/to=",
"requires": {
"hoek": "4.x.x",
"isemail": "2.x.x",
"items": "2.x.x",
"moment": "2.x.x",
"topo": "2.x.x"
}
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"junk": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/junk/-/junk-1.0.3.tgz",
"integrity": "sha1-h75jSIZJy9ym9Tqzm+yczSNH9ZI="
},
"maximatch": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",
"integrity": "sha1-hs2NawTJ8wfAWmuUGZBtA2D7E6I=",
"requires": {
"array-differ": "^1.0.0",
"array-union": "^1.0.1",
"arrify": "^1.0.0",
"minimatch": "^3.0.0"
}
},
"mime-db": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
},
"mime-types": {
"version": "2.1.21",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
"requires": {
"mime-db": "~1.37.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"moment": {
"version": "2.22.2",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
},
"nan": {
"version": "2.3.5",
"resolved": "http://registry.npmjs.org/nan/-/nan-2.3.5.tgz",
"integrity": "sha1-gioNwmYpDOTNOhIoLKPn42Rmigg="
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-is-inside": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
"integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pify": {
"version": "2.3.0",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"requires": {
"pinkie": "^2.0.0"
}
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"promise-streams": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/promise-streams/-/promise-streams-2.1.1.tgz",
"integrity": "sha1-cwnx02mDMOp/rasZIvE5iSKayFo=",
"requires": {
"bluebird": "^2.10.2"
}
},
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
},
"psl": {
"version": "1.1.29",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
},
"pty.js": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/pty.js/-/pty.js-0.3.1.tgz",
"integrity": "sha1-gfW+0zLW5eeraFaI0boDc0ENUbU=",
"requires": {
"extend": "~1.2.1",
"nan": "2.3.5"
}
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"recursive-copy": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/recursive-copy/-/recursive-copy-2.0.9.tgz",
"integrity": "sha512-0AkHV+QtfS/1jW01z3m2t/TRTW56Fpc+xYbsoa/bqn8BCYPwmsaNjlYmUU/dyGg9w8MmGoUWihU5W+s+qjxvBQ==",
"requires": {
"del": "^2.2.0",
"emitter-mixin": "0.0.3",
"errno": "^0.1.2",
"graceful-fs": "^4.1.4",
"junk": "^1.0.1",
"maximatch": "^0.1.0",
"mkdirp": "^0.5.1",
"pify": "^2.3.0",
"promise": "^7.0.1",
"slash": "^1.0.0"
}
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
}
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"requires": {
"glob": "^7.0.5"
}
},
"rx": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz",
"integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
},
"split": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
"requires": {
"through": "2"
}
},
"sshpk": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz",
"integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==",
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"stream-snitch": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/stream-snitch/-/stream-snitch-0.0.3.tgz",
"integrity": "sha1-iXp48TonFPqESqd74VR3qJbYUqk="
},
"through": {
"version": "2.3.8",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"topo": {
"version": "2.0.2",
"resolved": "http://registry.npmjs.org/topo/-/topo-2.0.2.tgz",
"integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=",
"requires": {
"hoek": "4.x.x"
}
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"urbit-runner": {
"version": "github:urbit/runner-js#ee2455015dc4ea243d0e0ec623975632c9249c4e",
"from": "github:urbit/runner-js#ee24550",
"requires": {
"colors": "^1.1.2",
"escape-string-regexp": "^1.0.5",
"once": "^1.4.0",
"promise-streams": "^2.1.1",
"pty.js": "^0.3.1",
"recursive-copy": "^2.0.7",
"split": "^1.0.1",
"stream-snitch": "0.0.3",
"wait-on": "^2.0.2"
}
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"wait-on": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.1.2.tgz",
"integrity": "sha512-Jm6pzZkbswtcRUXohxY1Ek5MrL16AwHj83drgW2FTQuglHuhZhVMyBLPIYG0rL1wvr5rdC1uzRuU/7Bc+B9Pwg==",
"requires": {
"core-js": "^2.4.1",
"joi": "^9.2.0",
"minimist": "^1.2.0",
"request": "^2.78.0",
"rx": "^4.1.0"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "arvo-tests",
"version": "1.0.0",
"description": "Test harness for Urbit arvo distribution",
"scripts": {
"test": "node test.js"
},
"private": true,
"author": "~fyr",
"license": "MIT",
"dependencies": {
"urbit-runner": "github:urbit/runner-js#ee24550"
}
}

View File

@ -0,0 +1 @@
https://ci-piers.urbit.org/zod-d71780001aed3ba464d8b24f223f6bc597236718.tgz

View File

@ -0,0 +1 @@
d0401f0034e348ec1db498f2c7884194d99b6de4

View File

@ -0,0 +1,17 @@
#!/bin/bash
set -euo pipefail
set -x
RESULT=$1
if [[ ${RESULT} -eq 0 ]]; then
exit 0
else
for i in $(find ./ -maxdepth 1 -name 'core*' -print)
do
gdb urbit core* -ex "thread apply all bt" -ex "set pagination 0" -batch
done
fi
echo "build failed with status code $RESULT"
exit $RESULT

134
pkg/arvo/.travis/test.js Normal file
View File

@ -0,0 +1,134 @@
'use strict';
var fs = require('fs')
var runner = require('urbit-runner')
var Urbit = runner.Urbit;
var ERROR = runner.ERROR;
var actions = runner.actions
var args = ['-B', 'urbit.pill', '-A', '..', '-cSF', 'zod', 'zod'];
var urbit = new Urbit(args);
// XX upstream this into runner-js
//
function rePill(urb) {
return new Promise(function(resolve,reject){
fs.stat('./built-pill/', function(err, stat) {
if (err) return resolve()
fs.readdir('./built-pill/', function(err, files) {
if (err || (1 !== files.length)) {
return resolve()
}
var name = files[0].replace(/\.pill$/, '')
urb.note('re-soliding pill')
return urb.expect(/dojo> /)
.then(function(){
return urb.line('|label %home %' + name)
})
.then(function(){
return urb.expect(/dojo> /)
})
.then(function(){
return urb.line('.latest/pill +solid /==/' + name + '/sys')
})
.then(function(){
return urb.expectEcho("%resolid")
})
.then(function(){
return urb.resetListeners();
})
.then(function(){
var write = fs.createWriteStream('./built-pill/' + name + '.pill')
var read = fs.createReadStream('./zod/.urb/put/latest.pill')
read.on('error', function(err){
return reject(err)
})
write.on('error', function(err){
return reject(err)
})
write.on('finish', function(){
return resolve()
})
return read.pipe(write)
})
// XX find a better way to add this to the promise chain
//
.then(function(){
return barMass(urb);
})
.catch(function(err){
return reject(err)
});
})
})
})
}
// XX upstream this into runner-js
//
function barMass(urb) {
return urb.line("|mass")
.then(function(){
return urb.expectEcho("%ran-mass")
.then(function(){ return urb.resetListeners(); })
})
}
function aqua(urb) {
return urb.line("|start %ph")
.then(function(){
return urb.line(":ph|init");
})
.then(function(){
return urb.line(":aqua &pill +solid");
})
.then(function(){
urb.every(/TEST [^ ]* FAILED/, function(arg){
throw Error(arg);
});
return urb.line(":ph|run %hi");
})
.then(function(){
return urb.expectEcho("ALL TESTS SUCCEEDED")
.then(function(){ return urb.resetListeners(); })
})
}
Promise.resolve(urbit)
.then(actions.safeBoot)
.then(function(){
return barMass(urbit);
})
.then(actions.test)
.then(actions.testCores)
.then(actions.testRenderers)
.then(function(){
return barMass(urbit);
})
.then(function(){
return aqua(urbit);
})
.then(function(){
return rePill(urbit);
})
.then(function(){
return urbit.expect(/dojo> /);
})
.then(function(){
return urbit.exit(0);
})
.catch(function(err){
return urbit.waitSilent()
.then(function(){
urbit.warn('Test aborted:', err);
return urbit.exit(1);
});
});

21
pkg/arvo/LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 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.

66
pkg/arvo/README.md Normal file
View File

@ -0,0 +1,66 @@
# Arvo
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.
If you're doing development on Arvo, keep reading.
## Documentation
Find Arvo's documentation [on urbit.org](https://urbit.org/docs/learn/arvo/).
## Development
To boot a fake ship from your development files, run `urbit` with the following arguments:
```
urbit -F zod -A /path/to/arvo -c fakezod
```
Mount Arvo's filesystem allows you to update its contents through Unix. To do so, run `|mount` in dojo. It is most common to `|mount /=home=`.
To create a custom pill (bootstrapping object) from the files loaded into the home desk, run `.my/pill +solid`. Your pill will appear in `/path/to/fakezod/.urb/put/my.pill`.
To boot a fake ship with a custom pill, use the `-B` flag:
```
urbit -F zod -A /path/to/arvo -B /path/to.pill -c fakezod
```
To run all tests in `/tests`, run `+test` in dojo. `+test /some/path` would only run all tests in `/tests/some/path`.
## Maintainers
Most parts of Arvo have dedicated maintainers.
* `/sys/hoon`: @pilfer-pandex (~pilfer-pandex)
* `/sys/zuse`: @pilfer-pandex (~pilfer-pandex)
* `/sys/arvo`: @jtobin (~nidsut-tomdun)
* `/sys/vane/ames`: @belisarius222 (~rovnys-ricfer) & @joemfb (~master-morzod)
* `/sys/vane/behn`: @belisarius222 (~rovnys-ricfer)
* `/sys/vane/clay`: @philipcmonk (~wicdev-wisryt)
* `/sys/vane/dill`: @bernardodelaplaz (~rigdyn-sondur)
* `/sys/vane/eyre`: @eglaysher (~littel-ponnys)
* `/sys/vane/ford`: @belisarius222 (~rovnys-ricfer) & @eglaysher (~littel-ponnys)
* `/sys/vane/gall`: @jtobin (~nidsut-tomdun)
* `/sys/vane/jael`: @fang- (~palfun-foslup) & @joemfb (~master-morzod)
* `/app/acme`: @joemfb (~master-morzod)
* `/app/dns`: @joemfb (~master-morzod)
* `/app/hall`: @fang- (~palfun-foslup)
* `/app/talk`: @fang- (~palfun-foslup)
* `/app/aqua`: @philipcmonk (~wicdev-wisryt)
* `/lib/test`: @eglaysher (~littel-ponnys)
## 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.
If you're looking to make code contributions, there are a few things you can do:
- 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.

57
pkg/arvo/TESTING.udon Normal file
View File

@ -0,0 +1,57 @@
:- ~[comments+&]
;>
# Writing Unit Tests
Urbit comes with a built in system for writing tests. Like hoon files with a
certain shape go in `%/app` or `%/gen` or `%/mar`, hoon files with a certain
shape can go in `%/tests` and then are exposed to a system wide test runner.
Say you put a test suite in `%/tests/new-hoon/thr.hoon`:
```
> +ls %/tests
new-hoon/
> +ls %/tests/new-hoon
ls/hoon mp/hoon myb/hoon thr/hoon
```
You can then just run that individual test suite (and not the ones that are beside it in the `%/tests/new-hoon` directory) with:
```
> +tests /new-hoon/thr
/new-hoon/thr/test-seconds OK
/new-hoon/thr/test-partition OK
/new-hoon/thr/test-firsts OK
/new-hoon/thr/test-apply OK
```
## The test file
So what is the structure of these test files? They contain a door, with arms starting with `++test-` or `++check-`. At minimum:
```
/+ *test
|%
++ test-some-test
(expect-eq !>(4) !>(4))
--
```
All of the utilities you need to write tests are in the tester library. Also, like other hoon files, you can stack cores for models and utility functions with only the final core being inspected for test arms.
## Some Details
So internally, how does this work?
The `+test` generator depends on each file/directory in `%/tests/` through a renderer. Each node in the filesystem tree is rendered by `%/ren/test-tree.hoon`, which calls itself recursively for subdirectories.
This means all compiling of test cases happens inside ford, which can cache work and not recompile tests whose dependencies haven't changed. At runtime, all the `+test` generator does is filter and execute tests from the tree.
I would like to get to a place where any direct scrying of the filesystem is discouraged, and almost everything flows through the functional reactive build system. This is what it is here for.
### Future distribution of hoon libraries
Implicit in having a standard way to write tests and a standard `+test` runner is the idea that all functionality on the current desk should be tested.
Let's say I'm shipping a program on Urbit and I use multiple third-party libraries. Each of those libraries should have their own test suites placed in `%/tests/`. When I `|merge` their desks into my application desk, having a standard test runner means that all their tests and all my application tests get run. If you're depending on a library, you want to make sure that the tests for your dependencies run when you test your application.

1394
pkg/arvo/app/acme.hoon Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
:: This needs a better SDN solution. Every ship should have an IP
:: address, and we should eventually test changing those IP
:: addresses.
::
:: For now, we broadcast every packet to every ship and rely on them
:: to drop them.
::
/- aquarium
=, aquarium
=> |%
+$ move (pair bone card)
+$ card
$% [%poke wire dock %aqua-events (list aqua-event)]
[%peer wire dock path]
[%pull wire dock ~]
==
::
+$ state
$: %0
subscribed=_|
==
--
=, gall
=| moves=(list move)
=| aqua-event-list=(list aqua-event)
=| ships=(list ship)
|_ $: bowl
state
==
++ this .
++ apex %_(this moves ~, aqua-event-list ~, ships ~)
++ abet
=? this !=(~ aqua-event-list)
%- emit-moves
[ost %poke /aqua-events [our %aqua] %aqua-events aqua-event-list]~
:: ~? !?=(~ moves) [%aqua-ames-moves (lent moves)]
[moves this]
::
++ emit-moves
|= ms=(list move)
%_(this moves (weld moves ms))
::
++ emit-aqua-events
|= aes=(list aqua-event)
%_(this aqua-event-list (weld aqua-event-list aes))
::
++ poke-aqua-vane-control
|= command=?(%subscribe %unsubscribe)
:_ this(subscribed =(command %subscribe))
(aqua-vane-control-handler our ost subscribed command)
::
:: Handle effects from ships. We only react to %send effects.
::
++ diff-aqua-effects
|= [way=wire afs=aqua-effects]
^- (quip move _this)
=. this apex =< abet
|- ^+ this
?~ ufs.afs
this
=. this
?+ -.q.i.ufs.afs this
%restore (handle-restore who.afs)
%send (handle-send i.ufs.afs)
==
$(ufs.afs t.ufs.afs)
::
++ handle-restore
|= who=@p
%- emit-aqua-events
[%event who [//newt/0v1n.2m9vh %barn ~]]~
::
++ handle-send
|= [way=wire %send lan=lane:ames pac=@]
^+ this
=/ hear [//newt/0v1n.2m9vh %hear lan pac]
=? ships =(~ ships)
.^((list ship) %gx /(scot %p our)/aqua/(scot %da now)/ships/noun)
%- emit-aqua-events
%+ turn ships
|= who=ship
[%event who hear]
--

131
pkg/arvo/app/aqua-behn.hoon Normal file
View File

@ -0,0 +1,131 @@
/- aquarium
=, aquarium
=> |%
+$ move (pair bone card)
+$ card
$% [%poke wire dock %aqua-events (list aqua-event)]
[%peer wire dock path]
[%pull wire dock ~]
[%wait wire p=@da]
[%rest wire p=@da]
==
::
+$ state
$: %0
subscribed=_|
piers=(map ship pier)
==
::
+$ pier next-timer=(unit @da)
--
=, gall
=| moves=(list move)
|_ $: bowl
state
==
++ this .
++ apex %_(this moves ~)
++ abet [(flop moves) this]
++ emit-moves
|= ms=(list move)
%_(this moves (weld ms moves))
::
++ emit-aqua-events
|= aes=(list aqua-event)
%- emit-moves
[ost %poke /aqua-events [our %aqua] %aqua-events aes]~
::
++ poke-aqua-vane-control
|= command=?(%subscribe %unsubscribe)
:_ this(subscribed =(command %subscribe))
(aqua-vane-control-handler our ost subscribed command)
::
++ diff-aqua-effects
|= [way=wire afs=aqua-effects]
^- (quip move _this)
=. this apex =< abet
|- ^+ this
?~ ufs.afs
this
=. this
?+ -.q.i.ufs.afs this
%sleep abet-pe:handle-sleep:(pe who.afs)
%restore abet-pe:handle-restore:(pe who.afs)
%doze abet-pe:(handle-doze:(pe who.afs) i.ufs.afs)
==
$(ufs.afs t.ufs.afs)
::
:: Received timer wake
::
++ wake
|= [way=wire error=(unit tang)]
^- (quip move _this)
=. this apex =< abet
?> ?=([@ *] way)
=/ who (,@p (slav %p i.way))
abet-pe:(take-wake:(pe who) t.way error)
::
++ pe
|= who=ship
=+ (~(gut by piers) who *pier)
=* pier-data -
|%
++ abet-pe
^+ this
=. piers (~(put by piers) who pier-data)
this
::
++ handle-sleep
^+ ..abet-pe
=< ..abet-pe(pier-data *pier)
?~ next-timer
..abet-pe
cancel-timer
::
++ handle-restore
^+ ..abet-pe
=. this
%- emit-aqua-events
[%event who [//behn/0v1n.2m9vh %born ~]]~
..abet-pe
::
++ handle-doze
|= [way=wire %doze tim=(unit @da)]
^+ ..abet-pe
?~ tim
?~ next-timer
..abet-pe
cancel-timer
?~ next-timer
(set-timer u.tim)
(set-timer:cancel-timer u.tim)
::
++ set-timer
|= tim=@da
~? debug=| [who=who %setting-timer tim]
=. next-timer `tim
=. this (emit-moves [ost %wait /(scot %p who) tim]~)
..abet-pe
::
++ cancel-timer
~? debug=| [who=who %cancell-timer (need next-timer)]
=. this (emit-moves [ost %rest /(scot %p who) (need next-timer)]~)
=. next-timer ~
..abet-pe
::
++ take-wake
|= [way=wire error=(unit tang)]
~? debug=| [who=who %aqua-behn-wake now error=error]
=. next-timer ~
=. this
%- emit-aqua-events
:_ ~
^- aqua-event
:+ %event who
:- //behn/0v1n.2m9vh
?~ error
[%wake ~]
[%crud %fail u.error]
..abet-pe
--
--

View File

@ -0,0 +1,78 @@
:: Would love to see a proper stateful terminal handler. Ideally,
:: you'd be able to ^X into the virtual ship, like the old ^W.
::
:: However, that's probably not the primary way of interacting with
:: it. In practice, most of the time you'll be running from a file
:: (eg for automated testing) or fanning the same command to multiple
:: ships or otherwise making use of the fact that we can
:: programmatically send events.
::
/- aquarium
=, aquarium
=> |%
+$ move (pair bone card)
+$ card
$% [%poke wire dock %aqua-events (list aqua-event)]
[%peer wire dock path]
[%pull wire dock ~]
==
::
+$ state
$: %0
subscribed=_|
==
--
=, gall
=| moves=(list move)
|_ $: bowl
state
==
++ this .
++ apex %_(this moves ~)
++ abet [(flop moves) this]
++ emit-moves
|= ms=(list move)
%_(this moves (weld ms moves))
::
++ emit-aqua-events
|= aes=(list aqua-event)
%- emit-moves
[ost %poke /aqua-events [our %aqua] %aqua-events aes]~
::
++ poke-aqua-vane-control
|= command=?(%subscribe %unsubscribe)
:_ this(subscribed =(command %subscribe))
(aqua-vane-control-handler our ost subscribed command)
::
++ diff-aqua-effects
|= [way=wire afs=aqua-effects]
^- (quip move _this)
=. this apex =< abet
|- ^+ this
?~ ufs.afs
this
=. this
?+ -.q.i.ufs.afs this
%blit (handle-blit who.afs i.ufs.afs)
==
$(ufs.afs t.ufs.afs)
::
++ handle-blit
|= [who=@p way=wire %blit blits=(list blit:dill)]
^+ this
=/ last-line
%+ roll blits
|= [b=blit:dill line=tape]
?- -.b
%lin (tape p.b)
%mor ~& "{<who>}: {line}" ""
%hop line
%bel line
%clr ""
%sag ~& [%save-jamfile-to p.b] line
%sav ~& [%save-file-to p.b] line
%url ~& [%activate-url p.b] line
==
~? !=(~ last-line) last-line
this
--

157
pkg/arvo/app/aqua-eyre.hoon Normal file
View File

@ -0,0 +1,157 @@
:: Pass-through Eyre driver
::
/- aquarium
=, aquarium
=> |%
+$ move (pair bone card)
+$ card
$% [%poke wire dock %aqua-events (list aqua-event)]
[%peer wire dock path]
[%pull wire dock ~]
[%hiss wire p=(unit user:eyre) q=mark r=(cask hiss:eyre)]
==
::
+$ state
$: %0
subscribed=_|
piers=(map ship pier)
==
::
+$ pier http-requests=(set @ud)
--
=, gall
=| moves=(list move)
|_ $: bowl
state
==
++ this .
++ apex %_(this moves ~)
++ abet [(flop moves) this]
++ emit-moves
|= ms=(list move)
%_(this moves (weld ms moves))
::
++ emit-aqua-events
|= aes=(list aqua-event)
%- emit-moves
[ost %poke /aqua-events [our %aqua] %aqua-events aes]~
::
++ poke-aqua-vane-control
|= command=?(%subscribe %unsubscribe)
:_ this(subscribed =(command %subscribe))
(aqua-vane-control-handler our ost subscribed command)
::
++ diff-aqua-effects
|= [way=wire afs=aqua-effects]
^- (quip move _this)
=. this apex =< abet
|- ^+ this
?~ ufs.afs
this
=. this
?+ -.q.i.ufs.afs this
%sleep abet-pe:handle-sleep:(pe who.afs)
%restore abet-pe:handle-restore:(pe who.afs)
%thus abet-pe:(handle-thus:(pe who.afs) i.ufs.afs)
==
$(ufs.afs t.ufs.afs)
::
:: Received inbound HTTP response
::
++ sigh-httr
|= [way=wire res=httr:eyre]
^- (quip move _this)
=. this apex =< abet
?> ?=([@ *] way)
=/ who (,@p (slav %p i.way))
~& [%received-httr who]
abet-pe:(take-sigh-httr:(pe who) t.way res)
::
:: Received inbound HTTP response error
::
++ sigh-tang
|= [way=wire tan=tang]
^- (quip move _this)
=. this apex =< abet
?> ?=([@ *] way)
=/ who (,@p (slav %p i.way))
~& [%received-httr who]
abet-pe:(take-sigh-tang:(pe who) t.way tan)
::
++ pe
|= who=ship
=+ (~(gut by piers) who *pier)
=* pier-data -
|%
++ abet-pe
^+ this
=. piers (~(put by piers) who pier-data)
this
::
++ handle-sleep
^+ ..abet-pe
..abet-pe(pier-data *pier)
::
++ handle-restore
^+ ..abet-pe
=. this
%- emit-aqua-events
[%event who [//http/0v1n.2m9vh %born ~]]~
..abet-pe
::
++ handle-thus
|= [way=wire %thus num=@ud req=(unit hiss:eyre)]
^+ ..abet-pe
?~ req
?. (~(has in http-requests) num)
..abet-pe
:: Eyre doesn't support cancelling HTTP requests from userspace,
:: so we remove it from our state so we won't pass along the
:: response.
::
~& [who=who %aqua-eyre-cant-cancel-thus num=num]
=. http-requests (~(del in http-requests) num)
..abet-pe
~& [who=who %aqua-eyre-requesting u.req]
=. http-requests (~(put in http-requests) num)
=. this
%- emit-moves :_ ~
:* ost
%hiss
/(scot %p who)/(scot %ud num)
~
%httr
[%hiss u.req]
==
..abet-pe
::
:: Pass HTTP response back to virtual ship
::
++ take-sigh-httr
|= [way=wire res=httr:eyre]
^+ ..abet-pe
?> ?=([@ ~] way)
=/ num (slav %ud i.way)
?. (~(has in http-requests) num)
~& [who=who %ignoring-httr num=num]
..abet-pe
=. http-requests (~(del in http-requests) num)
=. this
(emit-aqua-events [%event who [//http/0v1n.2m9vh %receive num [%start [p.res q.res] r.res &]]]~)
..abet-pe
::
:: Got error in HTTP response
::
++ take-sigh-tang
|= [way=wire tan=tang]
^+ ..abet-pe
?> ?=([@ ~] way)
=/ num (slav %ud i.way)
?. (~(has in http-requests) num)
~& [who=who %ignoring-httr num=num]
..abet-pe
=. http-requests (~(del in http-requests) num)
%- (slog tan)
..abet-pe
--
--

564
pkg/arvo/app/aqua.hoon Normal file
View File

@ -0,0 +1,564 @@
:: An aquarium of virtual ships. Put in some fish and watch them!
::
:: usage:
:: |start %aqua
:: /- aquarium
:: :aqua &pill .^(pill:aquarium %cx %/urbit/pill)
:: OR
:: :aqua &pill +solid
::
:: Then try stuff:
:: :aqua [%init ~[~bud ~dev]]
:: :aqua [%dojo ~[~bud ~dev] "[our eny (add 3 5)]"]
:: :aqua [%dojo ~[~bud] "|hi ~dev"]
:: :aqua [%wish ~[~bud ~dev] '(add 2 3)']
:: :aqua [%peek ~[~bud] /cx/~bud/home/(scot %da now)/app/curl/hoon]
:: :aqua [%dojo ~[~bud ~dev] '|mount %']
:: :aqua [%file ~[~bud ~dev] %/sys/vane]
:: :aqua [%pause-events ~[~bud ~dev]]
::
::
:: We get ++unix-event and ++pill from /-aquarium
::
/- aquarium
/+ pill
=, pill-lib=pill
=, aquarium
=> $~ |%
+$ move (pair bone card)
+$ card
$% [%diff diff-type]
==
::
:: Outgoing subscription updates
::
+$ diff-type
$% [%aqua-effects aqua-effects]
[%aqua-events aqua-events]
[%aqua-boths aqua-boths]
==
::
+$ state
$: %0
pil=pill
assembled=*
tym=@da
fleet-snaps=(map term (map ship pier))
piers=(map ship pier)
==
::
+$ pier
$: snap=*
event-log=(list unix-timed-event)
next-events=(qeu unix-event)
processing-events=?
==
--
=, gall
::
:: unix-{effects,events,boths}: collect jar of effects and events to
:: brodcast all at once to avoid gall backpressure
:: moves: Hoist moves into state for cleaner state management
::
=| unix-effects=(jar ship unix-effect)
=| unix-events=(jar ship unix-timed-event)
=| unix-boths=(jar ship unix-both)
=| moves=(list move)
|_ $: hid=bowl
state
==
::
:: Represents a single ship's state.
::
++ pe
|= who=ship
=+ (~(gut by piers) who *pier)
=* pier-data -
|%
::
:: Done; install data
::
++ abet-pe
^+ this
=. piers (~(put by piers) who pier-data)
this
::
:: Initialize new ship
::
++ apex
=. pier-data *pier
=. snap assembled
~& pill-size=(met 3 (jam snap))
..abet-pe
::
:: Enqueue events to child arvo
::
++ push-events
|= ues=(list unix-event)
^+ ..abet-pe
=. next-events (~(gas to next-events) ues)
..abet-pe
::
:: Send moves to host arvo
::
++ emit-moves
|= ms=(list move)
=. this (^emit-moves ms)
..abet-pe
::
:: Process the events in our queue.
::
++ plow
|- ^+ ..abet-pe
?: =(~ next-events)
..abet-pe
?. processing-events
..abet-pe
=^ ue next-events ~(get to next-events)
=/ poke-arm (mox +47.snap)
?> ?=(%0 -.poke-arm)
=/ poke p.poke-arm
=. tym (max +(tym) now.hid)
=/ poke-result (mule |.((slum poke tym ue)))
?: ?=(%| -.poke-result)
%- (slog >%aqua-crash< >guest=who< p.poke-result)
$
=. snap +.p.poke-result
=. ..abet-pe (publish-event tym ue)
=. ..abet-pe (handle-effects ((list ovum) -.p.poke-result))
$
::
:: Peek
::
++ peek
|= p=*
=/ res (mox +46.snap)
?> ?=(%0 -.res)
=/ peek p.res
=/ pax (path p)
?> ?=([@ @ @ @ *] pax)
=. i.t.t.t.pax (scot %da tym)
=/ pek (slum peek [tym pax])
pek
::
:: Wish
::
++ wish
|= txt=@t
=/ res (mox +22.snap)
?> ?=(%0 -.res)
=/ wish p.res
~& [who=who %wished (slum wish txt)]
..abet-pe
::
++ mox |=(* (mock [snap +<] scry))
::
:: Start/stop processing events. When stopped, events are added to
:: our queue but not processed.
::
++ start-processing-events .(processing-events &)
++ stop-processing-events .(processing-events |)
::
:: Handle all the effects produced by a single event.
::
++ handle-effects
|= effects=(list ovum)
^+ ..abet-pe
?~ effects
..abet-pe
=. ..abet-pe
=/ sof ((soft unix-effect) i.effects)
?~ sof
~? aqua-debug=| [who=who %unknown-effect i.effects]
..abet-pe
(publish-effect u.sof)
$(effects t.effects)
::
:: Give effect to our subscribers
::
++ publish-effect
|= uf=unix-effect
^+ ..abet-pe
=. unix-effects (~(add ja unix-effects) who uf)
=. unix-boths (~(add ja unix-boths) who [%effect uf])
..abet-pe
::
:: Give event to our subscribers
::
++ publish-event
|= ute=unix-timed-event
^+ ..abet-pe
=. event-log [ute event-log]
=. unix-events (~(add ja unix-events) who ute)
=. unix-boths (~(add ja unix-boths) who [%event ute])
..abet-pe
--
::
++ this .
::
:: ++apex-aqua and ++abet-aqua must bookend calls from gall
::
++ apex-aqua
^+ this
=: moves ~
unix-effects ~
unix-events ~
unix-boths ~
==
this
::
++ abet-aqua
^- (quip move _this)
=. this
%- emit-moves
%- zing ^- (list (list move))
%+ turn ~(tap by sup.hid)
|= [b=bone her=ship pax=path]
^- (list move)
?+ pax ~
[%effects @ ~]
=/ who (slav %p i.t.pax)
=/ ufs (~(get ja unix-effects) who)
?~ ufs
~
[b %diff %aqua-effects who (flop ufs)]~
::
[%effects ~]
%+ turn
~(tap by unix-effects)
|= [who=ship ufs=(list unix-effect)]
[b %diff %aqua-effects who (flop ufs)]
::
[%events @ ~]
=/ who (slav %p i.t.pax)
=/ ve (~(get ja unix-events) who)
?~ ve
~
[b %diff %aqua-events who (flop ve)]~
::
[%boths @ ~]
=/ who (slav %p i.t.pax)
=/ bo (~(get ja unix-boths) who)
?~ bo
~
[b %diff %aqua-boths who (flop bo)]~
==
[(flop moves) this]
::
++ emit-moves
|= ms=(list move)
=. moves (weld ms moves)
this
::
::
:: Run all events on all ships until all queues are empty
::
++ plow-all
|- ^+ this
=/ who
=/ pers ~(tap by piers)
|- ^- (unit ship)
?~ pers
~
?: &(?=(^ next-events.q.i.pers) processing-events.q.i.pers)
`p.i.pers
$(pers t.pers)
~? aqua-debug=| plowing=who
?~ who
this
=. this abet-pe:plow:(pe u.who)
$
::
:: Subscribe to effects from a ship
::
++ peer-effects
|= pax=path
^- (quip move _this)
?. ?=([@ *] pax)
~& [%aqua-bad-peer-effects pax]
`this
?~ (slaw %p i.pax)
~& [%aqua-bad-peer-effects-ship pax]
!!
`this
::
:: Subscribe to events to a ship
::
++ peer-events
|= pax=path
^- (quip move _this)
?. ?=([@ ~] pax)
~& [%aqua-bad-peer-events pax]
`this
?~ (slaw %p i.pax)
~& [%aqua-bad-peer-events-ship pax]
!!
`this
::
:: Subscribe to both events and effects of a ship
::
++ peer-boths
|= pax=path
^- (quip move _this)
?. ?=([@ ~] pax)
~& [%aqua-bad-peer-boths pax]
`this
?~ (slaw %p i.pax)
~& [%aqua-bad-peer-boths-ship pax]
!!
`this
::
:: Load a pill and assemble arvo. Doesn't send any of the initial
:: events.
::
++ poke-pill
|= p=pill
^- (quip move _this)
=. this apex-aqua =< abet-aqua
=. pil p
~& lent=(met 3 (jam boot-ova.pil))
=/ res=toon :: (each * (list tank))
(mock [boot-ova.pil [2 [0 3] [0 2]]] scry)
=. fleet-snaps ~
?- -.res
%0
~& %suc
=. assembled +7.p.res
this
::
%1
~& [%vere-blocked p.res]
this
::
%2
~& %vere-fail
%- (slog p.res)
this
==
::
:: Handle commands from CLI
::
:: Should put some thought into arg structure, maybe make a mark.
::
:: Should convert some of these to just rewrite into ++poke-events.
::
++ poke-noun
|= val=*
^- (quip move _this)
=. this apex-aqua =< abet-aqua
^+ this
:: Could potentially factor out the three lines of turn-ships
:: boilerplate
::
?+ val ~|(%bad-noun-arg !!)
[%swap-vanes vs=*]
?> ?=([[%7 * %1 installed=*] ~] boot-ova.pil)
=. installed.boot-ova.pil
%+ roll (,(list term) vs.val)
|= [v=term _installed.boot-ova.pil]
%^ slum installed.boot-ova.pil now.hid
=/ vane
?+ v ~|([%unknown-vane v] !!)
%a %ames
%b %behn
%c %clay
%d %dill
%e %eyre
%f %ford
%g %gall
%j %ford
==
=/ pax
/(scot %p our.hid)/home/(scot %da now.hid)/sys/vane/[vane]
=/ txt .^(@ %cx (weld pax /hoon))
[/vane/[vane] [%veer v pax txt]]
=> .(this ^+(this this))
=^ ms this (poke-pill pil)
(emit-moves ms)
::
[%swap-files ~]
=. userspace-ova.pil
=/ slim-dirs
`(list path)`~[/app /gen /lib /mar /sur /hoon/sys /arvo/sys /zuse/sys]
:_ ~
%- unix-event
%- %*(. file-ovum:pill-lib directories slim-dirs)
/(scot %p our.hid)/home/(scot %da now.hid)
=^ ms this (poke-pill pil)
(emit-moves ms)
::
[%wish hers=* p=@t]
%+ turn-ships ((list ship) hers.val)
|= [who=ship thus=_this]
=. this thus
(wish:(pe who) p.val)
::
[%unpause-events hers=*]
%+ turn-ships ((list ship) hers.val)
|= [who=ship thus=_this]
=. this thus
start-processing-events:(pe who)
::
[%pause-events hers=*]
%+ turn-ships ((list ship) hers.val)
|= [who=ship thus=_this]
=. this thus
stop-processing-events:(pe who)
::
[%clear-snap lab=@tas]
=. fleet-snaps ~ :: (~(del by fleet-snaps) lab.val)
this
==
::
:: Apply a list of events tagged by ship
::
++ poke-aqua-events
|= events=(list aqua-event)
^- (quip move _this)
=. this apex-aqua =< abet-aqua
%+ turn-events events
|= [ae=aqua-event thus=_this]
=. this thus
?- -.ae
%init-ship
=. this abet-pe:(publish-effect:(pe who.ae) [/ %sleep ~])
=/ initted
=< plow
%- push-events:apex:(pe who.ae)
^- (list unix-event)
:~ [/ %wack 0] :: eny
[/ %whom who.ae] :: eny
[//newt/0v1n.2m9vh %barn ~]
[//behn/0v1n.2m9vh %born ~]
:+ //term/1 %boot
?~ keys.ae
[%fake who.ae]
[%dawn u.keys.ae]
-.userspace-ova.pil
[//http/0v1n.2m9vh %born ~]
[//http/0v1n.2m9vh %live 8.080 `8.445]
==
=. this abet-pe:initted
(pe who.ae)
::
%pause-events
stop-processing-events:(pe who.ae)
::
%snap-ships
=. fleet-snaps
%+ ~(put by fleet-snaps) lab.ae
%- malt
%+ murn hers.ae
|= her=ship
^- (unit (pair ship pier))
=+ per=(~(get by piers) her)
?~ per
~
`[her u.per]
(pe -.hers.ae)
::
%restore-snap
=. this
%+ turn-ships (turn ~(tap by piers) head)
|= [who=ship thus=_this]
=. this thus
(publish-effect:(pe who) [/ %sleep ~])
=. piers (~(uni by piers) (~(got by fleet-snaps) lab.ae))
=. this
%+ turn-ships (turn ~(tap by piers) head)
|= [who=ship thus=_this]
=. this thus
(publish-effect:(pe who) [/ %restore ~])
(pe ~bud) :: XX why ~bud? need an example
::
%event
~? &(aqua-debug=| !?=(?(%belt %hear) -.q.ue.ae))
raw-event=[who.ae -.q.ue.ae]
~? &(debug=| ?=(%receive -.q.ue.ae))
raw-event=[who.ae ue.ae]
(push-events:(pe who.ae) [ue.ae]~)
==
::
:: Run a callback function against a list of ships, aggregating state
:: and plowing all ships at the end.
::
:: I think we should use patterns like this more often. Because we
:: don't, here's some points to be aware.
::
:: `fun` must take `this` as a parameter, since it needs to be
:: downstream of previous state changes. You could use `state` as
:: the state variable, but it muddles the code and it's not clear
:: whether it's better. You could use the `_(pe)` core if you're
:: sure you'll never need to refer to anything outside of your pier,
:: but I don't think we can guarantee that.
::
:: The callback function must start with `=. this thus`, or else
:: you don't get the new state. Would be great if you could hot-swap
:: that context in here, but we don't know where to put it unless we
:: restrict the callbacks to always have `this` at a particular axis,
:: and that doesn't feel right
::
++ turn-plow
|* arg=mold
|= [hers=(list arg) fun=$-([arg _this] _(pe))]
|- ^+ this
?~ hers
plow-all
=. this
abet-pe:plow:(fun i.hers this)
$(hers t.hers, this this)
::
++ turn-ships (turn-plow ship)
++ turn-events (turn-plow aqua-event)
::
:: Check whether we have a snapshot
::
++ peek-x-fleet-snap
|= pax=path
^- (unit (unit [%noun noun]))
?. ?=([@ ~] pax)
~
:^ ~ ~ %noun
(~(has by fleet-snaps) i.pax)
::
:: Pass scry into child ship
::
++ peek-x-i
|= pax=path
^- (unit (unit [%noun noun]))
?. ?=([@ @ @ @ @ *] pax)
~
=/ who (slav %p i.pax)
=/ pier (~(get by piers) who)
?~ pier
~
:^ ~ ~ %noun
(peek:(pe who) t.pax)
::
:: Get all created ships
::
++ peek-x-ships
|= pax=path
^- (unit (unit [%noun (list ship)]))
?. ?=(~ pax)
~
:^ ~ ~ %noun
`(list ship)`(turn ~(tap by piers) head)
::
:: Trivial scry for mock
::
++ scry |=([* *] ~)
::
:: Throw away old state if it doesn't soft to new state.
::
++ prep
|= old/(unit noun)
^- [(list move) _+>.$]
~& prep=%aqua
?~ old
`+>.$
=+ new=((soft state) u.old)
?~ new
`+>.$
`+>.$(+<+ u.new)
--

View File

@ -0,0 +1,332 @@
/+ tapp, stdio
=, able:kale
=> |%
+$ pending-udiffs (map number:block udiffs:point)
+$ config
$: url=@ta
from-number=number:block
==
+$ app-state ~
+$ peek-data ~
+$ in-poke-data
$% [%watch =config]
[%clear ~]
[%noun *]
==
+$ out-poke-data ~
+$ in-peer-data ~
+$ out-peer-data ~
++ tapp
%: ^tapp
app-state
peek-data
in-poke-data
out-poke-data
in-peer-data
out-peer-data
==
++ tapp-async tapp-async:tapp
++ stdio (^stdio out-poke-data out-peer-data)
--
::
:: Async helpers
::
=> |%
++ topics
=> azimuth-events:azimuth
:_ ~
:~ broke-continuity
changed-keys
lost-sponsor
escape-accepted
==
::
++ request-rpc
|= [url=@ta id=(unit @t) req=request:rpc:ethereum]
=/ m (async:stdio ,json)
^- form:m
%+ (retry json) `10
=/ m (async:stdio ,(unit json))
^- form:m
|^
=/ =request:http
:* method=%'POST'
url=url
header-list=['Content-Type'^'application/json' ~]
^= body
%- some %- as-octt:mimes:html
%- en-json:html
(request-to-json:rpc:ethereum id req)
==
;< ~ bind:m (send-request:stdio request)
;< rep=(unit client-response:iris) bind:m
take-maybe-response:stdio
?~ rep
(pure:m ~)
(parse-response u.rep)
::
++ parse-response
|= =client-response:iris
=/ m (async:stdio ,(unit json))
^- form:m
?> ?=(%finished -.client-response)
=/ body=@t q.data:(need full-file.client-response)
=/ jon=(unit json) (de-json:html body)
?~ jon
(pure:m ~)
=, dejs-soft:format
=/ array=(unit (list response:rpc:jstd))
((ar parse-one-response) u.jon)
?~ array
=/ res=(unit response:rpc:jstd) (parse-one-response u.jon)
?~ res
(async-fail:stdio %request-rpc-parse-error >id< ~)
?: ?=(%error -.u.res)
(async-fail:stdio %request-rpc-error >id< >+.res< ~)
?. ?=(%result -.u.res)
(async-fail:stdio %request-rpc-fail >u.res< ~)
(pure:m `res.u.res)
(async-fail:stdio %request-rpc-batch >%not-implemented< ~)
:: (pure:m `[%batch u.array])
::
++ parse-one-response
|= =json
^- (unit response:rpc:jstd)
=/ res=(unit [@t ^json])
%. json
=, dejs-soft:format
(ot id+so result+some ~)
?^ res `[%result u.res]
~| parse-one-response=json
:+ ~ %error %- need
%. json
=, dejs-soft:format
(ot id+so error+(ot code+no message+so ~) ~)
--
::
++ retry
|* result=mold
|= [crash-after=(unit @ud) computation=_*form:(async:stdio (unit result))]
=/ m (async:stdio ,result)
=| try=@ud
|^
|- ^- form:m
=* loop $
?: =(crash-after `try)
(async-fail:stdio %retry-too-many ~)
;< ~ bind:m (backoff try ~m1)
;< res=(unit result) bind:m computation
?^ res
(pure:m u.res)
loop(try +(try))
::
++ backoff
|= [try=@ud limit=@dr]
=/ m (async:stdio ,~)
^- form:m
;< eny=@uvJ bind:m get-entropy:stdio
;< now=@da bind:m get-time:stdio
%- wait:stdio
%+ add now
%+ min limit
?: =(0 try) ~s0
%+ add
(mul ~s1 (bex (dec try)))
(mul ~s0..0001 (~(rad og eny) 1.000))
--
::
++ get-latest-block
|= url=@ta
=/ m (async:stdio ,block)
^- form:m
;< =json bind:m (request-rpc url `'block number' %eth-block-number ~)
(get-block-by-number url (parse-eth-block-number:rpc:ethereum json))
::
++ get-block-by-number
|= [url=@ta =number:block]
=/ m (async:stdio ,block)
^- form:m
|^
;< =json bind:m
(request-rpc url `'block by number' %eth-get-block-by-number number |)
=/ =block (parse-block json)
?. =(number number.id.block)
(async-fail:stdio %reorg-detected >number< >block< ~)
(pure:m block)
::
++ parse-block
|= =json
^- block
=< [[&1 &2] |2]
^- [@ @ @]
~| json
%. json
=, dejs:format
%- ot
:~ hash+parse-hex-result:rpc:ethereum
number+parse-hex-result:rpc:ethereum
'parentHash'^parse-hex-result:rpc:ethereum
==
--
::
++ get-logs-by-hash
|= [url=@ta =hash:block]
=/ m (async:stdio udiffs:point)
^- form:m
;< =json bind:m
%+ request-rpc url
:* `'logs by hash'
%eth-get-logs-by-hash
hash
~[azimuth:contracts:azimuth]
topics
==
=/ event-logs=(list event-log:rpc:ethereum)
(parse-event-logs:rpc:ethereum json)
=/ =udiffs:point
%+ murn event-logs
|= =event-log:rpc:ethereum
^- (unit [=ship =udiff:point])
?~ mined.event-log
~
?: removed.u.mined.event-log
~& [%removed-log event-log]
~
=/ =id:block [block-hash block-number]:u.mined.event-log
=, azimuth-events:azimuth
=, abi:ethereum
?: =(broke-continuity i.topics.event-log)
=/ who=@ (decode-topics t.topics.event-log ~[%uint])
=/ num=@ (decode-results data.event-log ~[%uint])
`[who id %rift num]
?: =(changed-keys i.topics.event-log)
=/ who=@ (decode-topics t.topics.event-log ~[%uint])
=+ ^- [enc=octs aut=octs sut=@ud rev=@ud]
%+ decode-results data.event-log
~[[%bytes-n 32] [%bytes-n 32] %uint %uint]
`[who id %keys rev sut (pass-from-eth:azimuth enc aut sut)]
?: =(lost-sponsor i.topics.event-log)
=+ ^- [who=@ pos=@]
(decode-topics t.topics.event-log ~[%uint %uint])
`[who id %spon ~]
?: =(escape-accepted i.topics.event-log)
=+ ^- [who=@ wer=@]
(decode-topics t.topics.event-log ~[%uint %uint])
`[who id %spon `wer]
~& [%bad-topic event-log]
~
(pure:m udiffs)
::
++ jael-update
|= =udiffs:point
=/ m (async:stdio ,~)
|- ^- form:m
=* loop $
?~ udiffs
(pure:m ~)
~& > [%update block i.udiffs]
:: ;< ~ bind:m (send-effect [%vent-update i.udiffs])
loop(udiffs t.udiffs)
--
::
:: Main loop
::
=> |%
++ watch
|= =config
=/ m (async:stdio ,~)
^- form:m
=/ =number:block from-number.config
=| =pending-udiffs
=| blocks=(list block)
|- ^- form:m
=* poll-loop $
~& [%poll-loop number]
;< =latest=block bind:m (get-latest-block url.config)
|- ^- form:m
=* walk-loop $
~& [%walk-loop number]
?: (gth number number.id.latest-block)
;< now=@da bind:m get-time:stdio
;< ~ bind:m (wait:stdio (add now ~s10))
poll-loop
;< =block bind:m (get-block-by-number url.config number)
;< [=new=^pending-udiffs new-blocks=(lest ^block)] bind:m
(take-block url.config pending-udiffs block blocks)
=: pending-udiffs new-pending-udiffs
blocks new-blocks
number +(number.id.i.new-blocks)
==
walk-loop
::
++ take-block
|= [url=@ta =a=pending-udiffs =block blocks=(list block)]
=/ m (async:stdio ,[pending-udiffs (lest ^block)])
^- form:m
~& [%taking id.block]
?: &(?=(^ blocks) !=(parent-hash.block hash.id.i.blocks))
~& %rewinding
(rewind url a-pending-udiffs block blocks)
;< =b=pending-udiffs bind:m
(release-old-events a-pending-udiffs number.id.block)
;< =new=udiffs:point bind:m (get-logs-by-hash url hash.id.block)
~? !=(~ new-udiffs) [%adding-diffs new-udiffs]
=. b-pending-udiffs (~(put by b-pending-udiffs) number.id.block new-udiffs)
(pure:m b-pending-udiffs block blocks)
::
++ release-old-events
|= [=pending-udiffs =number:block]
=/ m (async:stdio ,^pending-udiffs)
^- form:m
=/ rel-number (sub number 30)
=/ =udiffs:point (~(get ja pending-udiffs) rel-number)
;< ~ bind:m (jael-update udiffs)
(pure:m (~(del by pending-udiffs) rel-number))
::
++ rewind
|= [url=@ta =pending-udiffs =block blocks=(list block)]
=/ m (async:stdio ,[^pending-udiffs (lest ^block)])
|- ^- form:m
=* loop $
~& [%wind block ?~(blocks ~ i.blocks)]
?~ blocks
(pure:m pending-udiffs block blocks)
?: =(parent-hash.block hash.id.i.blocks)
(pure:m pending-udiffs block blocks)
;< =next=^block bind:m (get-block-by-number url number.id.i.blocks)
?: =(~ pending-udiffs)
;< ~ bind:m (disavow block)
loop(block next-block, blocks t.blocks)
=. pending-udiffs (~(del by pending-udiffs) number.id.block)
loop(block next-block, blocks t.blocks)
::
++ disavow
|= =block
=/ m (async:stdio ,~)
^- form:m
(jael-update [*ship id.block %disavow ~]~)
--
::
:: Main
::
=* default-tapp default-tapp:tapp
%- create-tapp-poke-peer-take:tapp
|_ [=bowl:gall state=app-state]
++ handle-poke
|= =in-poke-data
=/ m tapp-async
^- form:m
?- -.in-poke-data
%noun (watch (config +.in-poke-data))
%watch (watch +.in-poke-data)
%clear !!
==
::
++ handle-take
|= =sign:tapp
!!
:: ?> ?=(%sources -.sign)
:: (handle-poke %watch +.sign)
::
++ handle-peer ~(handle-peer default-tapp bowl state)
--

658
pkg/arvo/app/chat.hoon Normal file
View File

@ -0,0 +1,658 @@
/- 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/
/~ ~
==
/= style
/^ octs
/; as-octs:mimes:html
/: /===/app/chat/css/index
/| /css/
/~ ~
==
/= chat-png
/^ (map knot @)
/: /===/app/chat/img /_ /png/
::
=, chat
::
|_ [bol=bowl:gall sta=state]
::
++ this .
::
:: +prep: set up the app, migrate the state once started
::
++ prep
|= old=(unit state)
^- (quip move _this)
=/ launcha/poke
[%launch-action [%chat /chattile '/~chat/js/tile.js']]
?~ old
=/ inboxpat /circle/inbox/config/group
=/ circlespat /circles/[(scot %p our.bol)]
=/ inboxwir /circle/[(scot %p our.bol)]/inbox/config/group
=/ inboxi/poke
:- %hall-action
[%source %inbox %.y (silt [[our.bol %i] ~]~)]
=/ fakeannounce=poke
:- %hall-action
[%create %hall-internal-announcements '' %village]
=/ announce=poke
:- %hall-action
[%create %announcements 'Announcements from Tlon' %journal]
=/ help=poke
:- %hall-action
[%create %urbit-help 'Get help about Urbit' %channel]
=/ dev=poke
:- %hall-action
[%create %urbit-dev 'Chat about developing on Urbit' %channel]
=/ sourcefakeannounce/poke
:- %hall-action
[%source %inbox %.y (silt [[our.bol %hall-internal-announcements] ~]~)]
=/ sourceannounce/poke
:- %hall-action
[%source %inbox %.y (silt [[~marzod %announcements] ~]~)]
=/ hallactions=(list move)
?: =((clan:title our.bol) %czar)
~
?: =(our.bol ~marzod)
~& %marzod-chat
:- [ost.bol %poke /announce [our.bol %hall] announce]
[ost.bol %poke /announce [our.bol %hall] sourceannounce]~
?: =(our.bol ~dopzod)
~& %dopzod-chat
:- [ost.bol %poke /announce [our.bol %hall] dev]
[ost.bol %poke /announce [our.bol %hall] help]~
:- [ost.bol %poke /announce [our.bol %hall] fakeannounce]
:- [ost.bol %poke /announce [our.bol %hall] sourcefakeannounce]
[ost.bol %poke /announce [our.bol %hall] sourceannounce]~
=/ moves=(list move)
:~ [ost.bol %peer inboxwir [our.bol %hall] inboxpat]
[ost.bol %peer circlespat [our.bol %hall] circlespat]
[ost.bol %connect / [~ /'~chat'] %chat]
[ost.bol %poke /chat [our.bol %hall] inboxi]
[ost.bol %poke /chat [our.bol %launch] launcha]
==
:_ this
%+ weld moves hallactions
:- [ost.bol %poke /chat [our.bol %launch] launcha]~
this(sta u.old)
::
++ construct-tile-json
|= str=streams
^- json
=/ numbers/(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)]
=/ maptjson=(map @t json)
%- my
:~ ['config' (config-to-json str)]
['numbers' (numbers-to-json numbers)]
==
[%o maptjson]
::
++ peer-chattile
|= wir=wire
^- (quip move _this)
:_ this
[ost.bol %diff %json (construct-tile-json str.sta)]~
::
:: +peer-messages: subscribe to subset of messages and updates
::
::
++ peer-primary
|= wir=wire
^- (quip move _this)
=* messages messages.str.sta
=/ lismov/(list move)
%+ murn ~(tap by messages)
|= [cir=circle:hall lis=(list envelope:hall)]
^- (unit move)
=/ envs/(unit (list envelope:hall)) (~(get by messages) cir)
?~ envs
~
=/ length/@ (lent u.envs)
=/ 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] u.envs)]
==
:_ this
[[ost.bol %diff %chat-config str.sta] lismov]
::
:: +poke-chat: send us an action
::
++ 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]
==
::
:: +send-chat-update: utility func for sending updates to all our subscribers
::
++ send-chat-update
|= [upd=update str=streams]
^- (list move)
=/ updates/(list move)
%+ turn (prey:pubsub:userlib /primary bol)
|= [=bone *]
[bone %diff %chat-update upd]
::
=/ jon/json (construct-tile-json str)
=/ tile-updates/(list move)
%+ turn (prey:pubsub:userlib /chattile bol)
|= [=bone *]
[bone %diff %json jon]
::
%+ weld
updates
tile-updates
::
::
:: +hall arms
::
::
:: +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 wire
::
%circles
?> ?=(%circles -.piz)
=/ str %= str.sta
circles cis.piz
==
:- (send-chat-update [[%circles cis.piz] str])
this(str.sta str)
::
:: %circle wire
::
%circle
:: ::
:: :: %circle prize
:: ::
:: %circle
?> ?=(%circle -.piz)
=/ circle/circle:hall [our.bol &3:wir]
?: =(circle [our.bol %inbox])
::
:: fill inbox config and remote configs with prize data
::
=/ configs
%- ~(uni in configs.str.sta)
^- (map circle:hall (unit config:hall))
(~(run by rem.cos.piz) |=(a=config:hall `a))
::
=/ circles/(list circle:hall)
%+ turn ~(tap in src.loc.cos.piz)
|= src=source:hall
^- circle:hall
cir.src
::
=/ meslis/(list [circle:hall (list envelope:hall)])
%+ turn circles
|= cir=circle:hall
^- [circle:hall (list envelope:hall)]
[cir ~]
::
=/ localpeers/(set @p)
%- silt %+ turn ~(tap by loc.pes.piz)
|= [shp=@p stat=status:hall]
shp
::
=/ peers/(map circle:hall (set @p))
%- ~(rep by rem.pes.piz)
|= [[cir=circle:hall grp=group:hall] acc=(map circle:hall (set @p))]
^- (map circle:hall (set @p))
=/ newset
%- silt %+ turn ~(tap by grp)
|= [shp=@p stat=status:hall]
shp
(~(put by acc) cir newset)
::
:-
%+ turn ~(tap in (~(del in (silt circles)) [our.bol %inbox]))
|= cir=circle:hall
^- move
=/ wir/wire /circle/[(scot %p our.bol)]/[nom.cir]/config/group
=/ pat/path /circle/[nom.cir]/config/group
[ost.bol %peer wir [our.bol %hall] pat]
::
%= this
inbox.str.sta loc.cos.piz
configs.str.sta configs
messages.str.sta (molt meslis)
peers.str.sta (~(put by peers) [our.bol %inbox] localpeers)
==
::
:: fill remote configs with message data
::
=* messages messages.str.sta
=/ circle/circle:hall [`@p`(slav %p &2:wir) &3:wir]
=/ localpeers/(set @p)
%- silt %+ turn ~(tap by loc.pes.piz)
|= [shp=@p stat=status:hall]
shp
::
=/ peers/(map circle:hall (set @p))
%- ~(rep by rem.pes.piz)
|= [[cir=circle:hall grp=group:hall] acc=(map circle:hall (set @p))]
^- (map circle:hall (set @p))
=/ newset
%- silt %+ turn ~(tap by grp)
|= [shp=@p stat=status:hall]
shp
(~(put by acc) cir newset)
=/ str
%= str.sta
messages (~(put by messages) circle nes.piz)
peers (~(uni by peers.str.sta) (~(put by peers) circle localpeers))
==
=/ messageupdate/update
:* %messages
circle
0
(lent messages)
nes.piz
==
:- (send-chat-update [messageupdate str])
this(str.sta str)
==
::
:: +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
%circles
?> ?=(%circles -.rum)
=/ cis
?: add.rum
(~(put in circles.str.sta) cir.rum)
(~(del in circles.str.sta) cir.rum)
=/ str
%= str.sta
circles cis
peers
?: add.rum
(~(put by peers.str.sta) [our.bol cir.rum] ~)
(~(del by peers.str.sta) [our.bol cir.rum])
==
:- (send-chat-update [[%circles cis] str])
this(str.sta str)
::
::
:: %circle: fill remote configs with message data
::
%circle
?> ?=(%circle -.rum)
=* sto rum.rum
?+ -.sto
[~ this]
::
:: %gram:
::
%gram
?> ?=(%gram -.sto)
=* messages messages.str.sta
=/ circle/circle:hall [`@p`(slav %p &2:wir) &3:wir]
=/ unes/(unit (list envelope:hall)) (~(get by messages) circle)
?~ unes
[~ this]
=/ nes u.unes
=/ str
%= str.sta
messages (~(put by messages) circle (snoc nes nev.sto))
==
:- (send-chat-update [[%message circle nev.sto] str])
this(str.sta str)
::
:: %status:
::
%status
?> ?=(%status -.sto)
=/ upeers/(unit (set @p)) (~(get by peers.str.sta) cir.sto)
?~ upeers
[~ this]
=/ peers/(set @p)
?: =(%remove -.dif.sto)
(~(del in u.upeers) who.sto)
(~(put in u.upeers) who.sto)
=/ str
%= str.sta
peers (~(put by peers.str.sta) cir.sto peers)
==
:- (send-chat-update [[%peers cir.sto peers] str])
this(str.sta str)
::
:: %config: config has changed
::
%config
=* circ cir.sto
::
?+ -.dif.sto
[~ this]
::
:: %full: set all of config without side effects
::
%full
=* conf cof.dif.sto
=/ str
%= str.sta
configs (~(put by configs.str.sta) circ `conf)
==
:- (send-chat-update [[%config circ conf] str])
this(str.sta str)
::
:: %read: the read count of one of our configs has changed
::
%read
?: =(circ [our.bol %inbox])
:: ignore when circ is inbox
[~ this]
=/ uconf/(unit config:hall) (~(got by configs.str.sta) circ)
?~ uconf
:: should we crash?
[~ this]
=/ conf/config:hall
%= u.uconf
red red.dif.sto
==
=/ str
%= str.sta
configs (~(put by configs.str.sta) circ `conf)
==
:- (send-chat-update [[%config circ conf] str])
this(str.sta str)
::
:: %source: the sources of our inbox have changed
::
%source
?. =(circ [our.bol %inbox])
:: ignore when circ is not inbox
[~ this]
=* affectedcir cir.src.dif.sto
=/ newwir/wire
/circle/[(scot %p hos.affectedcir)]/[nom.affectedcir]/grams/0/config/group
=/ pat/path /circle/[nom.affectedcir]/grams/0/config/group
:: we've added a source to our inbox
::
?: add.dif.sto
=/ newinbox %= inbox.str.sta
src (~(put in src.inbox.str.sta) src.dif.sto)
==
=/ str
%= str.sta
inbox newinbox
::
configs
?: (~(has by configs.str.sta) affectedcir)
configs.str.sta
(~(put by configs.str.sta) affectedcir ~)
==
::
:_ this(str.sta str)
%+ weld
[ost.bol %peer newwir [hos.affectedcir %hall] pat]~
(send-chat-update [[%inbox newinbox] str])
::
=/ newinbox %= inbox.str.sta
src (~(del in src.inbox.str.sta) src.dif.sto)
==
:: we've removed a source from our inbox
::
=/ str
%= str.sta
inbox newinbox
::
configs (~(del by configs.str.sta) affectedcir)
messages (~(del by messages.str.sta) affectedcir)
peers (~(del by peers.str.sta) affectedcir)
==
=/ fakecir/circle:hall
:- our.bol
%- crip
%+ weld (trip 'hall-internal-') (trip nom.affectedcir)
::
?~ (~(get by configs.str) fakecir)
:: just forward the delete to our clients
::
:_ this(str.sta str)
%+ weld
[ost.bol %pull newwir [hos.affectedcir %hall] ~]~
%+ weld
(send-chat-update [[%inbox newinbox] str])
(send-chat-update [[%delete affectedcir] str])
:: if we get a delete from another ship, delete our fake circle copy
::
=/ deletefake/poke
:- %hall-action
[%delete nom.fakecir ~]
:_ this(str.sta str)
%+ weld
[ost.bol %pull newwir [hos.affectedcir %hall] ~]~
%+ weld
[ost.bol %poke /fake [our.bol %hall] deletefake]~
%+ weld
(send-chat-update [[%inbox newinbox] str])
(send-chat-update [[%delete affectedcir] str])
::
:: %remove: remove a circle
::
%remove
=/ str
%= str.sta
configs (~(del by configs.str.sta) circ)
messages (~(del by messages.str.sta) circ)
peers (~(del by peers.str.sta) circ)
==
:- (send-chat-update [[%delete circ] str])
this(str.sta str)
::
==
:: end of branching on dif.sto type
==
:: end of branching on sto type
==
:: end of i.wir branching
::
:: +lient arms
::
::
:: +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/circle:hall [(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.sta
=/ 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/json %- 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.sta) [[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.sta) [[shp &3:wir] ~])
:_ this
[ost.bol %peer wir [shp %hall] pat]~
[~ this]
::
%circles
:_ this
[ost.bol %peer wir [our.bol %hall] wir]~
==
::
--

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<title>Chat</title>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<link rel="stylesheet" href="/~chat/css/index.css" />
</head>
<body>
<div id="root" />
<script src="/~/channel/channel.js"></script>
<script src="/~modulo/session.js"></script>
<script src="/~chat/js/index.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

896
pkg/arvo/app/claz.hoon Normal file
View File

@ -0,0 +1,896 @@
:: claz: command line azimuth, for the power-user
::
/- sole-sur=sole
/+ sole-lib=sole
::
=, azimuth
=, ethereum
=, rpc
=, key
::
|%
++ state
$: cli=shell
inp=in-progress
==
::
:: state & commands
::
++ shell
$: id=bone
say=sole-share:sole-sur
==
::
++ command
$% [%generate =path =network as=address =batch]
==
::
++ network
$? %main
%ropsten
%fake
[%other id=@]
==
::
++ batch
$~ [%deed '{}']
$% :: %single: execute a single ecliptic function call
::
[%single =call]
:: %deed: deed ships based on json, assumes spawnable
::
[%deed deeds-json=cord]
:: %lock-prep: prepare for lockup by transfering ships to the ceremony address
::
[%lock-prep what=(list ship)]
:: %lock: put ships into lockup for the target address
::
[%lock how=?(%spawn %transfer) what=(list ship) to=address =lockup]
:: %more: multiple batches sequentially
::
[%more batches=(list batch)]
==
::
++ lockup
$% [%linear windup-years=@ud unlock-years=@ud]
[%conditional [b1=@ud b2=@ud b3=@ud] unlock-years-per-batch=@ud]
==
::
++ rights
$: own=address
manage=(unit address)
voting=(unit address)
transfer=(unit address)
spawn=(unit address)
net=(unit [crypt=@ux auth=@ux])
==
::
++ call
$% [%create-galaxy gal=ship to=address]
[%spawn who=ship to=address]
[%configure-keys who=ship crypt=@ auth=@]
[%set-management-proxy who=ship proxy=address]
[%set-voting-proxy who=ship proxy=address]
[%set-spawn-proxy who=ship proxy=address]
[%transfer-ship who=ship to=address]
[%set-transfer-proxy who=ship proxy=address]
[%adopt who=ship]
==
::
:: monadic structures
::
:: in-progress: monad currently in progress
::
++ in-progress
%- unit
$% [%command command=eval-form:eval:null-glad]
==
::
:: null-glad: monad that produces nothing, "just effects"
::
++ null-glad (glad ,~)
::
:: glad-input: ~ for initialization, value for node response
::
++ glad-input (unit response:rpc:jstd)
::
:: glad-output-raw: moves + intermediate monad state/result
::
++ glad-output-raw
|* a=mold
$~ [~ %done *a]
$: moves=(list move)
$= next
$% [%wait ~]
[%cont self=(glad-form-raw a)]
[%fail err=tang]
[%done value=a]
==
==
::
:: glad-form-raw: shape of monad function
::
++ glad-form-raw
|* a=mold
$-(glad-input (glad-output-raw a))
::
:: glad-fail: procudes failure result
::
++ glad-fail
|= err=tang
|= glad-input
[~ %fail err]
::
:: glad: monad object for monads that produce moves at intermediate steps
::
++ glad
|* a=mold
|%
++ output (glad-output-raw a)
++ form (glad-form-raw a)
::
:: pure: produce intermediate result
::
++ pure
|= arg=a
^- form
|= glad-input
[~ %done arg]
::
:: bind: run m-b until it's done. once done, call fun with its result
::
++ bind
|* b=mold
|= [m-b=(glad-form-raw b) fun=$-(b form)]
^- form
|= input=glad-input
=/ b-res=(glad-output-raw b)
(m-b input)
^- output
:- moves.b-res
?- -.next.b-res
%wait [%wait ~]
%cont [%cont ..$(m-b self.next.b-res)]
%fail [%fail err.next.b-res]
%done [%cont (fun value.next.b-res)]
==
::
:: eval: call take with the latest input to kick monad object into action
::
++ eval
|%
+$ eval-form
$: =form
==
::
:: from-form: eval-form from form
::
++ from-form
|= =form
^- eval-form
form
::
:: eval-result: how far +take got
::
+$ eval-result
$% [%next ~]
[%fail err=tang]
[%done value=a]
==
::
:: take: run the monad operations as far as they can go right now
::
++ take
=| moves=(list move)
|= [=eval-form =our=wire =glad-input]
^- [[(list move) =eval-result] _eval-form]
:: run the current function
::
=/ =output (form.eval-form glad-input)
:: add moves
::
=. moves
(weld moves moves.output)
:: case-wise handle next steps
::
?- -.next.output
%wait [[moves %next ~] eval-form]
%fail [[moves %fail err.next.output] eval-form]
%done [[moves %done value.next.output] eval-form]
::
%cont
:: recurse to run continuation (next function in monad),
:: which is always started off with "initialization" input
::
%_ $
form.eval-form self.next.output
glad-input ~
==
==
--
--
::
:: effects
::
++ move (pair bone card)
++ card
$% [%hiss wire ~ mark %hiss hiss:eyre]
[%info wire desk nori:clay]
[%rest wire @da]
[%wait wire @da]
==
::
:: constants
::
++ ecliptic `address`0x6ac0.7b7c.4601.b5ce.11de.8dfe.6335.b871.c7c4.dd4d
--
::
|_ [=bowl:gall state]
++ this .
::
:: entrypoints
::
++ prep
|= old=(unit *)
^- (quip move _this)
[~ ..prep]
::
++ poke-noun
|= =command
^- (quip move _this)
:: create active monad, store in state
::
=. inp
%- some
:- %command
%- from-form:eval:null-glad
(deal-with-command command)
:: kick off monad
::
(take-command-sigh / ~)
::
++ sigh-tang-nonce
|= [=wire =tang]
^- (quip move _this)
=. tang [leaf+"claz failed" tang]
[~ (fail-command tang)]
::
++ sigh-json-rpc-response-command
|= [=wire =response:rpc:jstd]
^- (quip move _this)
(take-command-sigh wire `response)
::
++ take-command-sigh
|= [=wire response=glad-input]
^- (quip move _this)
:: we expect this to be called only if we have an in-progress monad
::
?~ inp
~|(%no-in-progress !!)
:: ?. ?=(%command -.u.inp) ::NOTE mint-vain rn
:: ~|([%unexpected-response -.u.inp] !!)
:: kick in-progress monad with response, updating it with the next callable
:: it spits out
::
=/ m null-glad
=^ r=[moves=(list move) =eval-result:eval:m] command.u.inp
(take:eval:m command.u.inp wire response)
:- moves.r
:: continue depending on the eval result
::
?- -.eval-result.r
:: not done, don't change app state further
::
%next this
:: failed, clean & update app state
::
%fail (fail-command err.eval-result.r)
:: succeeded, finalize & update app state
::
%done (done-command value.eval-result.r)
==
::
:: monadic helpers
::
:: fail-command: handle fail of nonce-fetching monad
::
++ fail-command
|= err=tang
^+ this
~& 'command processing failed'
::TODO error printing
this(inp ~)
::
:: done-command: handle result of nonce-fetching monad
::
++ done-command
|= ~
^+ this
~& %command-done
this(inp ~)
::
:: just-do: emit effects from monad without further processing
::
++ just-do
|= =move
^- form:null-glad
|= glad-input
[[move ~] %done ~]
::
:: get-next-nonce: monad function for fetching a nonce
::
++ get-next-nonce
|= for=address
=/ m (glad ,@ud)
^- form:m
;< =json bind:m
%+ do-request-expect-json-result `'some-id'
^- request
[%eth-get-transaction-count for]
^- form:m
?. ?=(%s -.json)
(glad-fail *tang) ::TODO proper error, "unexpected json"
%- pure:m
(rash p.json ;~(pfix (jest '0x') hex))
::
++ do-request
|= [rid=(unit @t) =request]
%+ do-hiss %json-rpc-response
^- hiss:eyre
%+ json-request
::TODO vary per network
(need (de-purl:html 'http://eth-mainnet.urbit.org:8545'))
(request-to-json rid request)
::
++ do-hiss
|= [=mark =hiss:eyre]
^- form:null-glad
|= glad-input
^- output:null-glad
=- [[[ost.bowl -] ~] %done ~]
::TODO wire in sample?
[%hiss /command ~ %json-rpc-response %hiss hiss]
::
++ expect-response
=/ m (glad response:rpc:jstd)
^- form:m
|= in=glad-input
?~ in [~ %wait ~]
[~ %done u.in]
::
++ do-request-expect-json-result
|= [rid=(unit @) =request]
=/ m (glad json)
;< ~ bind:m
(do-request rid request)
;< =response:rpc:jstd bind:m
expect-response
?. ?=(%result -.response)
(glad-fail *tang) ::TODO make pretty error message
(pure:m res.response)
::
:: transaction generation logic
::
++ deal-with-command
|= =command
=/ m null-glad
^- form:m
;< nonce=@ud bind:m (get-next-nonce as.command)
^- form:m
%- just-do
?- -.command
%generate
%+ write-file-transactions
path.command
(batch-to-transactions nonce [network as batch]:command)
==
::
++ batch-to-transactions
|= [nonce=@ud =network as=address =batch]
^- (list transaction)
?- -.batch
%single [(single nonce network as +.batch) ~]
%deed (deed nonce network as +.batch)
%lock-prep (lock-prep nonce network as +.batch)
%lock (lock nonce network as +.batch)
::
%more
=| txs=(list transaction)
=* batches batches.batch
|-
?~ batches txs
=/ new-txs=(list transaction)
^$(batch i.batches)
%_ $
txs (weld txs new-txs)
nonce (add nonce (lent new-txs))
batches t.batches
==
==
::
++ tape-to-ux
|= t=tape
(scan t zero-ux)
::
++ zero-ux
;~(pfix (jest '0x') hex)
::
++ write-file-transactions
|= [pax=path tox=(list transaction)]
^- move
?> ?=([@ desk @ *] pax)
:* ost.bowl
%info
(weld /write pax)
:: our.bowl
`desk`i.t.pax
=- &+[t.t.t.pax -]~
=/ y .^(arch %cy pax)
?~ fil.y
ins+eth-txs+!>(tox)
mut+eth-txs+!>(tox)
==
::
++ do
::TODO maybe reconsider encode-call interface, if we end up wanting @ux
:: as or more often than we want tapes
|= [=network nonce=@ud to=address dat=$@(@ux tape)]
^- transaction
:* nonce
8.000.000.000 ::TODO global config
600.000 ::TODO global config
to
0
`@`?@(dat dat (tape-to-ux dat))
?- network
%main 0x1
%ropsten 0x3
%fake `@ux``@`1.337
[%other *] id.network
==
==
::
++ single
|= [nonce=@ud =network as=address =call]
^- transaction
=- (do network nonce ecliptic -)
?- -.call
%create-galaxy (create-galaxy:dat +.call)
%spawn (spawn:dat +.call)
%configure-keys (configure-keys:dat +.call)
%set-management-proxy (set-management-proxy:dat +.call)
%set-voting-proxy (set-voting-proxy:dat +.call)
%set-spawn-proxy (set-spawn-proxy:dat +.call)
%transfer-ship (transfer-ship:dat +.call)
%set-transfer-proxy (set-transfer-proxy:dat +.call)
%adopt (adopt:dat +.call)
==
::
++ deed
|= [nonce=@ud =network as=address deeds-json=cord]
^- (list transaction)
=/ deeds=(list [=ship rights])
(parse-registration deeds-json)
::TODO split per spawn proxy
=| txs=(list transaction)
|^ :: $
?~ deeds (flop txs)
=* deed i.deeds
=. txs
?. ?=(%czar (clan:title ship.deed))
%- do-here
(spawn:dat ship.deed as)
~| %galaxy-held-by-ceremony
?> =(0x740d.6d74.1711.163d.3fca.cecf.1f11.b867.9a7c.7964 as)
~& [%assuming-galaxy-owned-by-ceremony ship.deed]
txs
=? txs ?=(^ net.deed)
%- do-here
(configure-keys:dat [ship u.net]:deed)
=? txs ?=(^ manage.deed)
%- do-here
(set-management-proxy:dat [ship u.manage]:deed)
=? txs ?=(^ voting.deed)
%- do-here
(set-voting-proxy:dat [ship u.voting]:deed)
=? txs ?=(^ spawn.deed)
%- do-here
(set-spawn-proxy:dat [ship u.spawn]:deed)
=. txs
%- do-here
(transfer-ship:dat [ship own]:deed)
$(deeds t.deeds)
::
::TODO maybe-do, take dat gat and unit argument
++ do-here
|= dat=tape
:_ txs
(do network (add nonce (lent txs)) ecliptic dat)
--
::
++ parse-registration
|= reg=cord
^- (list [=ship rights])
~| %registration-json-insane
=+ jon=(need (de-json:html reg))
~| %registration-json-invalid
?> ?=(%o -.jon)
=. p.jon (~(del by p.jon) 'idCode')
%+ turn ~(tap by p.jon)
|= [who=@t deed=json]
^- [ship rights]
:- (rash who dum:ag)
?> ?=(%a -.deed)
:: array has contents of:
:: [owner, transfer, spawn, mgmt, delegate, auth_key, crypt_key]
~| [%registration-incomplete deed (lent p.deed)]
?> =(7 (lent p.deed))
=< :* (. 0 %address) :: owner
(. 3 %unit-address) :: management
(. 4 %unit-address) :: voting
(. 1 %unit-address) :: transfer
(. 2 %unit-address) :: spawn
(both (. 6 %key) (. 5 %key)) :: crypt, auth
==
|* [i=@ud what=?(%address %unit-address %key)]
=+ j=(snag i p.deed)
~| [%registration-invalid-value what j]
?> ?=(%s -.j)
%+ rash p.j
=+ adr=;~(pfix (jest '0x') hex)
?- what
%address adr
%unit-address ;~(pose (stag ~ adr) (cold ~ (jest '')))
%key ;~(pose (stag ~ hex) (cold ~ (jest '')))
==
::
++ lock-prep
|= [nonce=@ud =network as=address what=(list ship)]
^- (list transaction)
=| txs=(list transaction)
|^
?~ what (flop txs)
=. txs
%- do-here
(spawn:dat i.what as)
=. txs
%- do-here
%+ transfer-ship:dat i.what
~& %assuming-lockup-done-by-ceremony
0x740d.6d74.1711.163d.3fca.cecf.1f11.b867.9a7c.7964
$(what t.what)
++ do-here
|= dat=tape
:_ txs
(do network (add nonce (lent txs)) ecliptic dat)
--
::
::TODO support distinguishing/switching between usable lockup methods
:: automagically
++ lock
|= $: nonce=@ud
=network
as=address
how=?(%spawn %transfer)
what=(list ship)
to=address
=lockup
==
^- (list transaction)
:: verify lockup sanity
::
~| %invalid-lockup-ships
?> ?| ?=(%linear -.lockup)
=(`@`(lent what) :(add b1.lockup b2.lockup b3.lockup))
==
:: expand galaxies into stars
::
=. what
%- zing
%+ turn what
|= s=ship
^- (list ship)
?. =(%czar (clan:title s)) [s]~
(turn (gulf 1 255) |=(k=@ud (cat 3 s k)))
=/ lockup-contract=address
?- -.lockup
%linear 0x86cd.9cd0.992f.0423.1751.e376.1de4.5cec.ea5d.1801
%conditional 0x8c24.1098.c3d3.498f.e126.1421.633f.d579.86d7.4aea
==
%- flop
=| txs=(list transaction)
^+ txs
|^
:: registration
::
=. txs
%+ do-here lockup-contract
?- -.lockup
%linear (register-linear to (lent what) +.lockup)
%conditional (register-conditional to +.lockup)
==
:: context-dependent setup
::
=. txs
?- how
:: %spawn: set spawn proxy of parents
::
%spawn
~& %assuming-ceremony-controls-parents
=/ parents
=- ~(tap in -)
%+ roll what
|= [s=ship ss=(set ship)]
?> =(%king (clan:title s))
(~(put in ss) (^sein:title s))
|-
?~ parents txs
=. txs
%+ do-here ecliptic
(set-spawn-proxy:dat i.parents lockup-contract)
$(parents t.parents)
::
:: %transfer: set transfer proxy of stars
::
%transfer
~& %assuming-ceremony-controls-stars
|-
?~ what txs
=. txs
%+ do-here ecliptic
(set-transfer-proxy:dat i.what lockup-contract)
$(what t.what)
==
:: depositing
::
|-
?~ what txs
=. txs
%+ do-here lockup-contract
(deposit:dat to i.what)
$(what t.what)
++ do-here
|= [contract=address dat=tape]
:_ txs
(do network (add nonce (lent txs)) contract dat)
--
::
++ register-linear
|= [to=address stars=@ud windup-years=@ud unlock-years=@ud]
%- register-linear:dat
:* to
(mul windup-years yer:yo)
stars
(div (mul unlock-years yer:yo) stars)
1
==
::
++ register-conditional
|= [to=address [b1=@ud b2=@ud b3=@ud] unlock-years-per-batch=@ud]
%- register-conditional:dat
=- [`address`to b1 b2 b3 `@ud`- 1]
(div (mul unlock-years-per-batch yer:yo) :(add b1 b2 b3))
::
:: call data generation
::TODO most of these should later be cleaned and go in ++constitution
::
++ dat
|%
++ enc
|* cal=$-(* call-data)
(cork cal encode-call)
::
++ create-galaxy (enc create-galaxy:cal)
++ spawn (enc spawn:cal)
++ configure-keys (enc configure-keys:cal)
++ set-spawn-proxy (enc set-spawn-proxy:cal)
++ transfer-ship (enc transfer-ship:cal)
++ set-management-proxy (enc set-management-proxy:cal)
++ set-voting-proxy (enc set-voting-proxy:cal)
++ set-transfer-proxy (enc set-transfer-proxy:cal)
++ set-dns-domains (enc set-dns-domains:cal)
++ upgrade-to (enc upgrade-to:cal)
++ transfer-ownership (enc transfer-ownership:cal)
++ adopt (enc adopt:cal)
++ register-linear (enc register-linear:cal)
++ register-conditional (enc register-conditional:cal)
++ deposit (enc deposit:cal)
--
::
++ cal
|%
++ create-galaxy
|= [gal=ship to=address]
^- call-data
?> =(%czar (clan:title gal))
:- 'createGalaxy(uint8,address)'
^- (list data)
:~ [%uint `@`gal]
[%address to]
==
::
++ spawn
|= [who=ship to=address]
^- call-data
?> ?=(?(%king %duke) (clan:title who))
:- 'spawn(uint32,address)'
:~ [%uint `@`who]
[%address to]
==
::
++ configure-keys
|= [who=ship crypt=@ auth=@]
::TODO maybe disable asserts?
?> (lte (met 3 crypt) 32)
?> (lte (met 3 auth) 32)
:- 'configureKeys(uint32,bytes32,bytes32,uint32,bool)'
:~ [%uint `@`who]
[%bytes-n 32^crypt]
[%bytes-n 32^auth]
[%uint 1]
[%bool |]
==
::
++ set-management-proxy
|= [who=ship proxy=address]
^- call-data
:- 'setManagementProxy(uint32,address)'
:~ [%uint `@`who]
[%address proxy]
==
::
++ set-voting-proxy
|= [who=ship proxy=address]
^- call-data
:- 'setVotingProxy(uint8,address)'
:~ [%uint `@`who]
[%address proxy]
==
::
++ set-spawn-proxy
|= [who=ship proxy=address]
^- call-data
:- 'setSpawnProxy(uint16,address)'
:~ [%uint `@`who]
[%address proxy]
==
::
++ transfer-ship
|= [who=ship to=address]
^- call-data
:- 'transferPoint(uint32,address,bool)'
:~ [%uint `@`who]
[%address to]
[%bool |]
==
::
++ set-transfer-proxy
|= [who=ship proxy=address]
^- call-data
:- 'setTransferProxy(uint32,address)'
:~ [%uint `@`who]
[%address proxy]
==
::
++ set-dns-domains
|= [pri=tape sec=tape ter=tape]
^- call-data
:- 'setDnsDomains(string,string,string)'
:~ [%string pri]
[%string sec]
[%string ter]
==
::
++ upgrade-to
|= to=address
^- call-data
:- 'upgradeTo(address)'
:~ [%address to]
==
::
::
++ transfer-ownership :: of contract
|= to=address
^- call-data
:- 'transferOwnership(address)'
:~ [%address to]
==
::
++ adopt
|= who=ship
^- call-data
:- 'adopt(uint32)'
:~ [%uint `@`who]
==
::
::
++ register-linear
|= $: to=address
windup=@ud
stars=@ud
rate=@ud
rate-unit=@ud
==
^- call-data
:- 'register(address,uint256,uint16,uint16,uint256)'
:~ [%address to]
[%uint windup]
[%uint stars]
[%uint rate]
[%uint rate-unit]
==
::
++ register-conditional
|= $: to=address
b1=@ud
b2=@ud
b3=@ud
rate=@ud
rate-unit=@ud
==
^- call-data
:- 'register(address,uint16[],uint16,uint256)'
:~ [%address to]
[%array ~[uint+b1 uint+b2 uint+b3]]
[%uint rate]
[%uint rate-unit]
==
::
++ deposit
|= [to=address star=ship]
^- call-data
:- 'deposit(address,uint16)'
:~ [%address to]
[%uint `@`star]
==
--
::
:: ++ peer-sole
:: |= =path
:: =. id.cli ost.bowl
:: TODO...
:: ::
:: ++ sh
:: |_ she=shell
:: ::
:: :: # %resolve
:: +| %resolve
:: ::
:: ++ sh-done
:: :: stores changes to the cli.
:: ::
:: ^+ +>
:: +>(cli she)
:: ::
:: :: #
:: :: # %emitters
:: :: #
:: :: arms that create outward changes.
:: +| %emitters
:: ::
:: ++ sh-fact
:: :: adds a console effect to ++ta's moves.
:: ::
:: |= fec/sole-effect:sole-sur
:: ^+ +>
:: +>(moves [[id.she %diff %sole-effect fec] moves])
:: ::
:: ++ sh-prod
:: :: show prompt
:: ::
:: :: makes and stores a move to modify the cli
:: :: prompt to display the current audience.
:: ::
:: ^+ .
:: %+ sh-fact %pro
:: :+ & %talk-line
:: ^- tape
:: =/ rew/(pair (pair cord cord) audience)
:: [['[' ']'] active.she]
:: =+ cha=(~(get by bound) q.rew)
:: ?^ cha ~[u.cha ' ']
:: =+ por=~(ar-prom ar q.rew)
:: (weld `tape`[p.p.rew por] `tape`[q.p.rew ' ' ~])
:: ::
:: --
--

80
pkg/arvo/app/clock.hoon Normal file
View File

@ -0,0 +1,80 @@
/+ *server
/= tile-js
/^ octs
/; as-octs:mimes:html
/: /===/app/clock/js/tile
/| /js/
/~ ~
==
=, format
::
|%
:: +move: output effect
::
+$ move [bone card]
:: +card: output effect payload
::
+$ poke
$% [%launch-action [@tas path @t]]
==
::
+$ card
$% [%poke wire dock poke]
[%http-response =http-event:http]
[%connect wire binding:eyre term]
[%diff %json json]
==
::
--
::
|_ [bol=bowl:gall ~]
::
++ this .
::
++ bound
|= [wir=wire success=? binding=binding:eyre]
^- (quip move _this)
[~ this]
::
++ prep
|= old=(unit ~)
^- (quip move _this)
=/ launcha
[%launch-action [%clock /tile '/~clock/js/tile.js']]
:_ this
:~
[ost.bol %connect / [~ /'~clock'] %clock]
[ost.bol %poke /clock [our.bol %launch] launcha]
==
::
++ peer-tile
|= pax=path
^- (quip move _this)
[[ost.bol %diff %json *json]~ this]
::
++ send-tile-diff
|= jon=json
^- (list move)
%+ turn (prey:pubsub:userlib /tile bol)
|= [=bone ^]
[bone %diff %json jon]
::
++ 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)
=/ back-path (flop site.request-line)
=/ name=@t
=/ back-path (flop site.request-line)
?~ back-path
''
i.back-path
::
?~ back-path
[[ost.bol %http-response not-found:app]~ this]
?: =(name 'tile')
[[ost.bol %http-response (js-response:app tile-js)]~ this]
[[ost.bol %http-response not-found:app]~ this]
::
--

File diff suppressed because one or more lines are too long

895
pkg/arvo/app/dns-bind.hoon Normal file
View File

@ -0,0 +1,895 @@
/- *dns-bind, dns, hall
/+ tapp, stdio
::
:: tapp types and boilerplate
::
=> |%
++ collector-app `dock`[~zod %dns-collector]
+$ app-state
$: %0
:: nem: authoritative state
::
nem=(unit nameserver)
==
+$ peek-data _!!
+$ in-poke-data
$% [%dns-authority =authority]
[%dns-bind =ship =target]
[%handle-http-request =inbound-request:eyre]
==
+$ out-poke-data
$% [%dns-bind =ship =target]
[%dns-complete =ship =binding:dns]
[%drum-unlink =dock]
==
+$ in-peer-data
$% [%dns-request =request:dns]
==
+$ out-peer-data ~
++ tapp
%: ^tapp
app-state
peek-data
in-poke-data
out-poke-data
in-peer-data
out-peer-data
==
++ tapp-async tapp-async:tapp
++ stdio (^stdio out-poke-data out-peer-data)
--
::
:: oauth2 implementation
::
=> |%
:: +oauth2-config: as one would expect
::
+$ oauth2-config
$: auth-url=@t
exchange-url=@t
domain=turf
initial-path=path
redirect-path=path
scopes=(list @t)
==
:: +oauth2: library core
::
++ oauth2
|_ [our=@p now=@da config=oauth2-config code=@t =hart:eyre secrets=@t]
::
++ local-uri
|= [our=ship =path]
^- @t
:: XX can't scry in +mule
::
:: =/ =hart:eyre .^(hart:eyre %e /(scot %p our)/host/real)
(crip (en-purl:html [hart [~ path] ~]))
::
:: XX can't scry in +mule
::
:: ++ code
:: ^- @t
:: %- crip
:: +:(scow %p .^(@p %j /(scot %p our)/code/(scot %da now)/(scot %p our)))
::
:: to initialize these values: |init-oauth2 /com/googleapis
::
++ oauth2-secrets
^- [client-id=@t client-secret=@t]
=; =wain
?> ?=([@t @t ~] wain)
[i.wain i.t.wain]
::
%- to-wain:format
%- need
%+ de:crub:crypto code
%+ slav %uw
:: XX can't scry in +mule
::
:: .^(@ %cx :(weld /(scot %p our)/home/(scot %da now)/sec domain.config /atom))
secrets
::
++ initial-uri (local-uri our initial-path.config)
++ redirect-uri (local-uri our redirect-path.config)
::
++ redirect-to-provider
^- @t
=/ url (need (de-purl:html auth-url.config))
=. r.url
:* ['access_type' 'offline']
['response_type' 'code']
['prompt' 'consent']
['client_id' client-id:oauth2-secrets]
['redirect_uri' redirect-uri]
['scope' (rap 3 (join ' ' scopes.config))]
r.url
==
(crip (en-purl:html url))
::
++ retrieve-access-token
|= code=@t
^- request:http
=/ hed
:~ ['Accept' 'application/json']
['Content-Type' 'application/x-www-form-urlencoded']
==
=/ bod
%- some %- as-octt:mimes:html
%- tail %- tail:en-purl:html
:~ ['client_id' client-id:oauth2-secrets]
:: note: required, unused parameter
::
['redirect_uri' redirect-uri]
['client_secret' client-secret:oauth2-secrets]
['grant_type' 'authorization_code']
['code' code]
==
[%'POST' exchange-url.config hed bod]
::
++ parse-token-response
|= =octs
^- (unit [access=@t expires=@u refresh=@t])
%. q.octs
;~ biff
de-json:html
=, dejs-soft:format
(ot 'access_token'^so 'expires_in'^ni 'refresh_token'^so ~)
==
:: XX implement
::
++ refresh-token !!
--
--
::
:: helpers
::
=> |%
:: +name: fully-qualified domain name for :ship
::
++ name
|= [=ship =turf]
(cat 3 (en-turf:html (weld turf /(crip +:(scow %p ship)))) '.')
:: +lame: domain name for :ship (without trailing '.')
::
++ lame
|= [=ship =turf]
(en-turf:html (weld turf /(crip +:(scow %p ship))))
:: +endpoint: append :path to :purl
::
++ endpoint
|= [=purl:eyre =path]
^+ purl
purl(q.q (weld q.q.purl path))
:: +params: append :params to :purl
::
++ params
|= [=purl:eyre =quay:eyre]
^+ purl
purl(r (weld r.purl quay))
:: +json-octs: deserialize json and apply reparser
::
++ json-octs
|* [bod=octs wit=fist:dejs:format]
=/ jon (de-json:html q.bod)
?~ jon ~
(wit u.jon)
:: +ship-turf: parse ship from first subdomain
::
++ ship-turf
|= [nam=@t aut-dom=turf]
^- (unit ship)
=/ dom=(unit host:eyre)
(rush nam ;~(sfix thos:de-purl:html dot))
?: ?| ?=(~ dom)
?=(%| -.u.dom)
?=(~ p.u.dom)
==
~
=/ who
(rush (head (flop p.u.dom)) fed:ag)
?~ who ~
?. =(aut-dom (flop (tail (flop p.u.dom))))
~
:: galaxies always excluded
::
?: ?=(%czar (clan:title u.who))
~
who
--
::
:: service providers
::
=> |%
:: +provider: initialize provider-specific core
::
++ provider
|= aut=authority
?- -.pro.aut
%fcloud ~(. fcloud aut)
%gcloud ~(. gcloud aut)
==
:: |fcloud: Cloudflare provider
::
++ fcloud
=> |%
++ parse-raw-record
|= aut-dom=turf
^- $- json
(unit [=ship id=@ta tar=target])
=, dejs:format
%+ cu
|= [id=@t typ=@t nam=@t dat=@t]
^- (unit [=ship id=@ta tar=target])
:: XX fix this
::
=/ him (ship-turf (cat 3 nam '.') aut-dom)
?: ?=(~ him)
~
?+ typ
~
::
%'A'
=/ adr (rush dat lip:ag)
?~ adr ~
`[u.him `@ta`id %direct %if u.adr]
::
%'CNAME'
:: XX fix this
::
=/ for (ship-turf (cat 3 dat '.') aut-dom)
?~ for ~
`[u.him `@ta`id %indirect u.for]
==
:: XX parse dates, proxied, ttl?
::
%- ot :~
'id'^so
'type'^so
'name'^so
'content'^so
==
--
::
|_ aut=authority
:: +base: provider service endpoint
::
++ base
^- purl:eyre
(need (de-purl:html 'https://api.cloudflare.com/client/v4'))
:: +headers: standard HTTP headers for all |fcloud requests
::
++ headers
|= aut=authority
?> ?=(%fcloud -.pro.aut)
%- ~(gas by *math:eyre)
:~ ['Content-Type' ['application/json' ~]]
['X-Auth-Email' [email.auth.pro.aut ~]]
['X-Auth-Key' [key.auth.pro.aut ~]]
==
:: +zone: provider-specific zone info request
::
++ zone
^- hiss:eyre
?> ?=(%fcloud -.pro.aut)
[(endpoint base /zones/[zone.pro.aut]) %get (headers aut) ~]
:: +record: JSON-formatted provider-specific dns record
::
++ record
|= [him=ship tar=target]
^- json
?> ?=(%fcloud -.pro.aut)
=/ type
?:(?=(%direct -.tar) 'A' 'CNAME')
=/ data
?: ?=(%direct -.tar)
(crip +:(scow %if p.tar))
(lame p.tar dom.aut)
:- %o
%- ~(gas by *(map @t json))
:~ ['name' %s (lame him dom.aut)]
['type' %s type]
['content' %s data]
:: XX make configureable?
::
['ttl' %n ~.1]
['proxied' %b %.n]
==
:: +create: provider-specific record-creation request
::
++ create
|= [him=ship tar=target pre=(unit [id=@ta tar=target])]
^- hiss:eyre
?> ?=(%fcloud -.pro.aut)
=/ bod=octs
%- as-octt:mimes:html
%- en-json:html
(record him tar)
?~ pre
:- (endpoint base /zones/[zone.pro.aut]/['dns_records'])
[%post (headers aut) `bod]
:- (endpoint base /zones/[zone.pro.aut]/['dns_records']/[id.u.pre])
[%put (headers aut) `bod]
:: +existing: list existing records stored by provider
::
++ existing
|= page=(unit @t)
^- hiss:eyre
?> ?=(%fcloud -.pro.aut)
:: XX more url params:
:: ?type ?per-page ?order ?direction
::
:- %+ params
(endpoint base /zones/[zone.pro.aut]/['dns_records'])
?~(page ~ ['page' u.page]~)
[%get (headers aut) ~]
:: +parse-list: existing records stored by provider
::
++ parse-list
^- $- json
(pair (list [=ship id=@ta tar=target]) (unit @t))
?> ?=(%fcloud -.pro.aut)
=, dejs:format
%+ cu
|= $: success=?
response=(list (unit [=ship id=@ta tar=target]))
paginate=[page=@ud per-page=@ud count=@ud total-count=@ud]
==
^- (pair (list [=ship id=@ta tar=target]) (unit @t))
?. success [~ ~]
:- (murn response same)
:: XX calculate next page number if applicable
::
~
:: XX parse errors and messages?
::
%- ot :~
'success'^bo
'result'^(ar (parse-raw-record dom.aut))
:- 'result_info'
%- ot :~
'page'^ni
'per_page'^ni
'count'^ni
'total_count'^ni
==
==
:: +parse-record: single record stored by provider
::
++ parse-record
^- $- json
(unit [=ship id=@ta tar=target])
?> ?=(%fcloud -.pro.aut)
=, dejs:format
%+ cu
|= [success=? response=(unit [=ship id=@ta tar=target])]
^- (unit [=ship id=@ta tar=target])
?. success ~
response
:: XX parse errors and messages?
::
%- ot :~
'success'^bo
'result'^(parse-raw-record dom.aut)
==
--
:: |gcloud: GCP provider
::
++ gcloud
|_ aut=authority
:: +base: provider service endpoint
::
++ base
^- purl:eyre
(need (de-purl:html 'https://www.googleapis.com/dns/v1/projects'))
:: +headers: standard HTTP headers for all |gcloud requests
::
++ headers
|= aut=authority
?> ?=(%gcloud -.pro.aut)
?. ?=(^ auth.pro.aut)
~| %gcloud-missing-auth !!
%- ~(gas by *math:eyre)
:~ ['Content-Type' ['application/json' ~]]
['Authorization' [`@t`(cat 3 'Bearer ' access.u.auth.pro.aut) ~]]
==
:: +zone: provider-specific zone info request
::
++ zone
^- hiss:eyre
?> ?=(%gcloud -.pro.aut)
:- (endpoint base /[project.pro.aut]/['managedZones']/[zone.pro.aut])
[%get (headers aut) ~]
:: +record: JSON-formatted provider-specific dns record
::
++ record
|= [him=ship tar=target]
^- json
?> ?=(%gcloud -.pro.aut)
=/ type
?:(?=(%direct -.tar) 'A' 'CNAME')
=/ data
?: ?=(%direct -.tar)
[%s (crip +:(scow %if p.tar))]
[%s (name p.tar dom.aut)]
:- %o
%- ~(gas by *(map @t json))
:~ ['name' %s (name him dom.aut)]
['type' %s type]
:: XX make configureable?
::
['ttl' %n ~.300]
['rrdatas' %a data ~]
==
:: +create: provider-specific record-creation request
::
++ create
=, eyre
|= [him=ship tar=target pre=(unit [id=@ta tar=target])]
^- hiss
?> ?=(%gcloud -.pro.aut)
=/ url=purl
%+ endpoint base
/[project.pro.aut]/['managedZones']/[zone.pro.aut]/changes
=/ bod=octs
%- as-octt:mimes:html
%- en-json:html
:- %o
%- ~(gas by *(map @t json))
:- ['additions' %a (record him tar) ~]
?~ pre ~
[['deletions' %a (record him tar.u.pre) ~] ~]
[url %post (headers aut) `bod]
:: +existing: list existing records stored by provider
::
++ existing
=, eyre
|= page=(unit @t)
^- hiss
?> ?=(%gcloud -.pro.aut)
=/ url=purl
%+ endpoint base
/[project.pro.aut]/['managedZones']/[zone.pro.aut]/rrsets
=/ hed=math (headers aut)
=? hed ?=(^ page)
(~(put by hed) 'pageToken' [u.page]~)
[url %get hed ~]
:: +parse-list: existing records stored by provider
::
++ parse-list
^- $- json
(pair (list [=ship id=@ta tar=target]) (unit @t))
?> ?=(%gcloud -.pro.aut)
=, dejs:format
=> |%
++ page (uf ~ (mu so))
++ records
%+ uf ~
%+ cu
|*(a=(list (unit)) (murn a same))
(ar parse-record)
--
:: XX parse but don't produce
:: 'kind'^(su (jest "dns#resourceRecordSetsListResponse'))
::
(ou 'rrsets'^records 'nextPageToken'^page ~)
:: +parse-record: single record stored by provider
::
++ parse-record
^- $- json
(unit [=ship id=@ta tar=target])
?> ?=(%gcloud -.pro.aut)
=, dejs:format
%+ cu
|= [typ=@t nam=@t dat=(list @t)]
^- (unit [=ship id=@ta tar=target])
:: gcloud doesn't expose UUIDs for bindings
::
=/ id %$
=/ him (ship-turf nam dom.aut)
?: |(?=(~ him) ?=(~ dat) ?=(^ t.dat))
~
?+ typ
~
::
%'A'
=/ adr (rush i.dat lip:ag)
?~ adr ~
`[u.him id %direct %if u.adr]
::
%'CNAME'
=/ for (ship-turf i.dat dom.aut)
?~ for ~
`[u.him id %indirect u.for]
==
::
%- ot :~
:: 'kind'^(su (jest "dns#resourceRecordSet'))
::
'type'^so
'name'^so
'rrdatas'^(ar so)
==
--
--
::
:: monadic helpers (XX move to stdio?)
::
=> |%
:: +backoff: exponential backoff timer
::
++ backoff
|= [try=@ud limit=@dr]
=/ m (async:stdio ,~)
^- form:m
;< eny=@uvJ bind:m get-entropy:stdio
;< now=@da bind:m get-time:stdio
%- wait:stdio
%+ add now
%+ min limit
?: =(0 try) ~s0
%+ add
(mul ~s1 (bex (dec try)))
(mul ~s0..0001 (~(rad og eny) 1.000))
::
++ request
|= =hiss:eyre
=/ m (async:stdio (unit httr:eyre))
^- form:m
;< ~ bind:m (send-hiss:stdio hiss)
take-maybe-sigh:stdio
::
++ request-retry
|= [=hiss:eyre max=@ud limit=@dr]
=/ m (async:stdio (unit httr:eyre))
=/ try=@ud 0
|- ^- form:m
=* loop $
?: =(try max)
(pure:m ~)
;< ~ bind:m (backoff try limit)
;< rep=(unit httr:eyre) bind:m (request hiss)
:: XX needs a better predicate. LTE will make this easier
::
?: &(?=(^ rep) =(200 p.u.rep))
(pure:m (some u.rep))
loop(try +(try))
--
::
:: application actions
::
=> |%
++ confirm-authority
|= =authority
=/ m (async:stdio ?)
^- form:m
;< rep=(unit httr:eyre) bind:m
(request-retry zone:(provider authority) 5 ~m10)
(pure:m &(?=(^ rep) =(200 p.u.rep)))
::
++ retrieve-existing
|= =authority
=/ m (async:stdio (map ship bound))
^- form:m
=| existing=(map ship bound)
=| next-page=(unit @t)
;< now=@da bind:m get-time:stdio
|- ^- form:m
=* loop $
;< rep=(unit httr:eyre) bind:m
(request-retry (existing:(provider authority) next-page) 5 ~m10)
?: ?| ?=(~ rep)
?=(~ r.u.rep)
==
(pure:m existing)
::
=* octs u.r.u.rep
=+ ^- [dat=(list [=ship id=@ta =target]) page=(unit @t)]
:: XX gross
::
=- ?~(- [~ ~] -)
(json-octs octs parse-list:(provider authority))
=. existing
|- ^+ existing
?~ dat
existing
=/ =bound [now id.i.dat target.i.dat ~]
$(dat t.dat, existing (~(put by existing) ship.i.dat bound))
?~ page
(pure:m existing)
loop(next-page page)
::
++ create-binding
|= [=authority =ship =target existing=(unit bound)]
=/ m (async:stdio (unit bound))
^- form:m
?: &(?=(^ existing) =(target cur.u.existing))
(pure:m existing)
::
=/ pre=(unit [@ta ^target])
?~(existing ~ (some [id cur]:u.existing))
;< rep=(unit httr:eyre) bind:m
(request (create:(provider authority) ship target pre))
:: XX retryable?
::
?. &(?=(^ rep) =(200 p.u.rep))
(pure:m ~)
::
=* httr u.rep
=/ id=@ta
?. ?=(%fcloud -.pro.authority) ~.
?. ?=(^ r.httr)
~| [%authority-create-confirm-id rep] !!
=/ dat=(unit [^ship id=@ta ^target])
(json-octs u.r.httr parse-record:(provider authority))
?~(dat ~. id.u.dat)
::
=/ =address:dns
?>(?=(%direct -.target) +.target)
=/ =turf
(weld dom.authority /(crip +:(scow %p ship)))
;< ~ bind:m (poke-app:stdio collector-app [%dns-complete ship address turf])
;< now=@da bind:m get-time:stdio
=/ =bound
[now id target ?~(existing ~ [[wen cur] hit]:u.existing)]
(pure:m (some bound))
::
++ initialize-authority
|= [aut=authority state=app-state]
=/ m tapp-async
^- form:m
?> ?=(^ nem.state)
=* nam u.nem.state
;< good=? bind:m (confirm-authority aut)
?. good
~& %dns-authority-failed
(pure:m state(nem ~))
::
:: XX wait-effect
::
;< existing=(map ship bound) bind:m (retrieve-existing aut)
=. bon.nam (~(uni by bon.nam) existing)
=. nem.state (some nam)
::
:: XX wait-effect
::
;< ~ bind:m (peer-app:stdio collector-app /requests)
(pure:m state)
--
::
:: |oauth2-core: configured oauth functionality (for |gcloud only)
::
=> |%
++ oauth2-core
|= [=bowl:gall code=@t =hart:eyre secrets=@t]
=/ =oauth2-config
:* auth-url='https://accounts.google.com/o/oauth2/v2/auth'
exchange-url='https://www.googleapis.com/oauth2/v4/token'
domain=/com/googleapis
redirect-path=/dns/oauth
initial-path=/dns/oauth/result
:~ 'https://www.googleapis.com/auth/ndev.clouddns.readwrite'
'https://www.googleapis.com/auth/cloud-platform.read-only'
== ==
~(. oauth2 our.bowl now.bowl oauth2-config code hart secrets)
--
::
:: the app itself
::
=* default-tapp default-tapp:tapp
%- create-tapp-all:tapp
^- tapp-core-all:tapp
|_ [=bowl:gall state=app-state]
::
++ handle-peek handle-peek:default-tapp
++ handle-peer handle-peer:default-tapp
::
++ handle-init
=/ m tapp-async
^- form:m
;< success=? bind:m (bind-route:stdio [~ /dns/oauth] dap.bowl)
~| %dns-unable-to-bind-route
?> success
;< ~ bind:m (poke-app:stdio [[our %hood] [%drum-unlink our dap]]:bowl)
(pure:m state)
::
++ handle-poke
|= =in-poke-data
=/ m tapp-async
^- form:m
?. (team:title [our src]:bowl)
~| %bind-yoself !!
?- -.in-poke-data
::
%dns-authority
?. =(~ nem.state)
~| %authority-reset-wat-do !!
=* aut authority.in-poke-data
=/ nam=nameserver [aut ~ ~]
=. nem.state (some nam)
:: XX move this into the provider interface
::
?: ?& ?=(%gcloud -.pro.aut)
?=(~ auth.pro.aut)
==
~& %do-the-oauth-thing
~& initial-uri:(oauth2-core bowl scry.pro.aut)
(pure:m state)
::
(initialize-authority aut state)
::
%dns-bind
?~ nem.state
~| %bind-not-authority !!
=* nam u.nem.state
=* who ship.in-poke-data
=* tar target.in-poke-data
?: ?=(%indirect -.tar)
~| %indirect-unsupported !!
:: defer %indirect where target isn't yet bound
::
:: ?: ?& ?=(%indirect -.tar)
:: !(~(has by bon.nam) p.tar)
:: ==
:: =. dep.nam (~(put ju dep.nam) p.tar [who tar])
:: =. nem.state (some nam)
:: (pure:m state)
=/ existing (~(get by bon.nam) who)
;< new=(unit bound) bind:m (create-binding aut.nam who tar existing)
?~ new
~& [%bind-failed in-poke-data]
(pure:m state)
=. bon.nam (~(put by bon.nam) who u.new)
=. nem.state (some nam)
::
:: XX wait-effect
::
=/ dep=(list [=ship =target])
~(tap in (~(get ju dep.nam) who))
|- ^- form:m
=* loop $
?~ dep
=. dep.nam (~(del by dep.nam) who)
=. nem.state (some nam)
(pure:m state)
;< ~ bind:m (poke-app:stdio [our dap]:bowl [%dns-bind ship target]:i.dep)
loop(dep t.dep)
::
:: XX need to %handle-http-cancel as well
::
%handle-http-request
:: always stash request bone for giving response
::
=/ =bone ost.bowl
:: XX maybe always (set-raw-contract %request) so transaction failure is captured?
::
=* inbound-request inbound-request.in-poke-data
?~ nem.state
~& :* %not-an-authority
%http-request
=> inbound-request
[authenticated secure address [method url]:request]
==
;< ~ bind:m
(send-effect-on-bone:stdio bone [%http-response %start [%403 ~] ~ %.y])
(pure:m state)
::
=* nam u.nem.state
?> ?=(%gcloud -.pro.aut.nam)
::
=/ parsed=(unit (pair pork:eyre quay:eyre))
%+ rush
url.request.inbound-request
;~(plug ;~(pose apat:de-purl:html (easy *pork:eyre)) yque:de-purl:html)
::
?. ?=(^ parsed)
~| [%invalid-url url.request.inbound-request] !!
=* url q.p.u.parsed
=* ext p.p.u.parsed
=* params q.u.parsed
::
?+ url
;< ~ bind:m
(send-effect-on-bone:stdio bone [%http-response %start [%404 ~] ~ %.y])
(pure:m state)
::
[%dns %oauth ~]
=/ link (trip redirect-to-provider:(oauth2-core bowl scry.pro.aut.nam))
=/ bod=(unit octs)
%- some
%- as-octt:mimes:html
%- en-xml:html
;html
;head
;title: :dns oauth
==
;body
;p make sure that the oauth credential is configured
with a redirect uri of {(trip redirect-uri:(oauth2-core bowl scry.pro.aut.nam))}
==
;a(href link): {link}
==
==
;< ~ bind:m
(send-effect-on-bone:stdio bone [%http-response %start [%200 ~] bod %.y])
(pure:m state)
::
[%dns %oauth %result ~]
=/ code (~(got by (my params)) %code)
:: XX make path configurable
::
=/ hed [['Location' '/dns/oauth/success'] ~]
::
;< ~ bind:m
(send-request:stdio (retrieve-access-token:(oauth2-core bowl scry.pro.aut.nam) code))
;< rep=(unit client-response:iris) bind:m
take-maybe-response:stdio
:: XX retry
::
?> ?& ?=(^ rep)
?=(%finished -.u.rep)
?=(^ full-file.u.rep)
==
=/ data (parse-token-response:oauth2 data.u.full-file.u.rep)
=. auth.pro.aut.nam (some [access refresh]:(need data))
=. nem.state (some nam)
:: XX use expiry to set refresh timer
::
:: XX may need to send this as a card so we don't wait
::
;< ~ bind:m
(send-effect-on-bone:stdio bone [%http-response %start [%301 hed] ~ %.y])
(initialize-authority aut.nam state)
::
[%dns %oauth %success ~]
=/ bod=(unit octs)
%- some
%- as-octt:mimes:html
%- en-xml:html
;html
;head
;title: :dns oauth
==
;body
;p: you may close the browser window
;p
;span: XX remove me
:: XX make path configurable
::
;a(href "/dns/oauth"): again
==
==
==
;< ~ bind:m (send-effect:stdio %http-response %start [%201 ~] bod %.y)
(pure:m state)
==
==
::
++ handle-diff
|= [=dock =path =in-peer-data]
=/ m tapp-async
^- form:m
?. =(dock collector-app)
(pure:m state)
=* req request.in-peer-data
=/ =target [%direct address.req]
;< ~ bind:m (poke-app:stdio [our dap]:bowl [%dns-bind ship.req target])
(pure:m state)
::
++ handle-take
|= =sign:tapp
=/ m tapp-async
^- form:m
?. ?=(%quit -.sign)
:: XX handle stuff
::
(pure:m state)
::
?. ?& =(dock.sign collector-app)
=(path.sign /requests)
==
~& [%unexpected-quit-wat-do [dock path]:sign]
(pure:m state)
::
;< ~ bind:m (peer-app:stdio collector-app /requests)
(pure:m state)
--

View File

@ -0,0 +1,158 @@
/- dns
::
:: app types and boilerplate
::
=> |%
+$ app-state
$: %0
requested=(map ship address:dns)
completed=(map ship binding:dns)
==
+$ peek-data [%noun (list (pair ship address:dns))]
+$ in-poke-data
$% [%dns-address =address:dns]
[%dns-complete =ship =binding:dns]
==
+$ out-poke-data
$% [%drum-unlink =dock]
==
+$ out-peer-data
$% [%dns-binding =binding:dns]
[%dns-request =request:dns]
==
+$ card
$% [%diff out-peer-data]
[%poke wire =dock out-poke-data]
==
+$ move [bone card]
--
::
=| moves=(list move)
|_ [=bowl:gall state=app-state]
::
++ this .
::
++ abet
^- (quip move _this)
[(flop moves) this(moves ~)]
::
++ emit
|= mov=move
^+ this
this(moves [mov moves])
::
++ emil
|= moz=(list move)
|- ^+ this
?~ moz
this
$(moz t.moz, ..this (emit i.moz))
::
++ poke-app
|= [=wire =dock =out-poke-data]
^+ this
(emit [ost.bowl %poke wire dock out-poke-data])
::
++ give-result
|= [=the=path =out-peer-data]
^+ this
%- emil
%+ turn
^- (list bone)
%+ murn ~(tap by sup.bowl)
|= [ost=bone =ship =sub=path]
`(unit bone)`?.(=(the-path sub-path) ~ (some ost))
|= =bone
[bone %diff out-peer-data]
::
++ prep
|= old=(unit app-state)
^- (quip move _this)
=< abet
?~ old
(poke-app /unlink [[our %hood] [%drum-unlink our dap]]:bowl)
this(state u.old)
::
++ poke
|= =in-poke-data
^- (quip move _this)
=< abet
?- -.in-poke-data
%dns-address
=* who src.bowl
=* adr address.in-poke-data
=/ rac (clan:title who)
?. ?=(?(%king %duke) rac)
~| [%dns-collector-bind-invalid who] !!
?: (reserved:eyre if.adr)
~| [%dns-collector-reserved-address who if.adr] !!
::
=/ req=(unit address:dns) (~(get by requested.state) who)
=/ dun=(unit binding:dns) (~(get by completed.state) who)
?: &(?=(^ dun) =(adr address.u.dun))
=. requested.state (~(del by requested.state) who)
(give-result /(scot %p who) %dns-binding u.dun)
::
?: &(?=(^ req) =(adr u.req))
this
:: XX check address?
=/ =request:dns [who adr]
=. requested.state (~(put by requested.state) request)
(give-result /requests %dns-request request)
::
%dns-complete
:: XX or confirm valid binding?
::
?. (team:title [our src]:bowl)
~| %complete-yoself !!
=* who ship.in-poke-data
=* adr address.binding.in-poke-data
=* tuf turf.binding.in-poke-data
=/ req=(unit address:dns) (~(get by requested.state) who)
:: ignore established bindings that don't match requested
::
?: ?& ?=(^ req)
!=(adr u.req)
==
this
=: requested.state (~(del by requested.state) who)
completed.state (~(put by completed.state) who [adr tuf])
==
(give-result /(scot %p who) %dns-binding adr tuf)
==
::
++ peek
|= =path
^- (unit (unit peek-data))
~& path
?+ path [~ ~]
[%x %requested ~]
[~ ~ %noun ~(tap by requested.state)]
==
::
++ peer
|= =path
^- (quip move _this)
=< abet
:: will be immediately unlinked, see +prep
::
?: ?=([%sole *] path)
this
?. ?=([@ ~] path)
~| %invalid-path !!
?: ?=(%requests i.path)
=/ requests ~(tap by requested.state)
|- ^+ this
=* loop $
?~ requests
this
=. ..this (give-result path %dns-request i.requests)
loop(requests t.requests)
::
=/ who (slaw %p i.path)
?~ who
~| %invalid-path !!
?~ dun=(~(get by completed.state) who)
this
(give-result path %dns-binding u.dun)
--

291
pkg/arvo/app/dns.hoon Normal file
View File

@ -0,0 +1,291 @@
/- dns, hall
/+ tapp, stdio
::
:: tapp types and boilerplate
::
=> |%
++ collector-app `dock`[~zod %dns-collector]
+$ app-state
$: %0
requested=(unit address:dns)
completed=(unit binding:dns)
==
+$ peek-data _!!
+$ in-poke-data
$% [%dns-auto ames-domains=(list turf)]
[%dns-address =address:dns]
==
+$ out-poke-data
$% [%dns-address =address:dns]
[%hall-action %phrase audience:hall (list speech:hall)]
==
+$ in-peer-data
$% [%dns-binding =binding:dns]
==
+$ out-peer-data ~
++ tapp
%: ^tapp
app-state
peek-data
in-poke-data
out-poke-data
in-peer-data
out-peer-data
==
++ stdio (^stdio out-poke-data out-peer-data)
--
::
:: monadic helpers (XX move to stdio?)
::
=> |%
:: +backoff: exponential backoff timer
::
++ backoff
|= [try=@ud limit=@dr]
=/ m (async:stdio ,~)
^- form:m
;< eny=@uvJ bind:m get-entropy:stdio
;< now=@da bind:m get-time:stdio
%- wait:stdio
%+ add now
%+ min limit
?: =(0 try) ~s0
%+ add
(mul ~s1 (bex (dec try)))
(mul ~s0..0001 (~(rad og eny) 1.000))
::
++ request
|= =hiss:eyre
=/ m (async:stdio (unit httr:eyre))
^- form:m
;< ~ bind:m (send-hiss:stdio hiss)
take-maybe-sigh:stdio
::
:: +self-check-http: confirm our availability at .host on port 80
::
:: XX needs better success/failure predicates
:: XX bind route to self and handle request inside tx?
::
++ self-check-http
|= [=host:eyre max=@ud]
=/ m (async:stdio ?)
^- form:m
:: XX also scry into eyre
:: q:.^(hart:eyre %e /(scot %p our)/host/real)
=/ =hiss:eyre
=/ url=purl:eyre
[[sec=| por=~ host] [ext=`~.udon path=/static] query=~]
[url %get ~ ~]
=/ try=@ud 0
|- ^- form:m
=* loop $
?: =(try max)
(pure:m |)
;< ~ bind:m (backoff try ~h1)
;< rep=(unit httr:eyre) bind:m (request hiss)
?: ?& ?=(^ rep)
|(=(200 p.u.rep) =(307 p.u.rep))
==
(pure:m &)
?. ?| ?=(~ rep)
=(504 p.u.rep)
==
(pure:m |)
loop(try +(try))
::
++ hall-app-message
|= [app=term =cord =tang]
=/ m (async:stdio ,~)
^- form:m
=/ msg=speech:hall
:+ %app app
=/ line [%lin & cord]
?~(tang line [%fat [%tank tang] line])
;< our=@p bind:m get-identity:stdio
=/ act
[%phrase (sy [our %inbox] ~) [msg ~]]
(poke-app:stdio [our %hall] %hall-action act)
--
::
:: application actions
::
=> |%
:: +turf-confirm-install: self check and install domain
::
++ turf-confirm-install
|= =turf
=/ m (async:stdio ?)
^- form:m
;< good=? bind:m (self-check-http &+turf 5)
?. good
(pure:m |)
;< ~ bind:m (install-domain:stdio turf)
(pure:m &)
::
:: +galaxy-domains
::
++ galaxy-domains
|= ames-domains=(list turf)
=/ m (async:stdio ,~)
^- form:m
;< our=@p bind:m get-identity:stdio
:: XX urbit/urbit#1314
::
:: ;< now=@da bind:m get-time:stdio
:: =/ ames-domains=(list turf)
:: .^((list turf) %j /(scot %p our)/turf/(scot %da now))
|- ^- form:m
=* loop $
?~ ames-domains
(pure:m ~)
=/ =turf
(weld i.ames-domains /(crip +:(scow %p our)))
;< good=? bind:m (turf-confirm-install turf)
=/ msg=(pair cord tang)
?: good
[(cat 3 'confirmed access via ' (en-turf:html turf)) ~]
:- (cat 3 'unable to access via ' (en-turf:html turf))
:~ leaf+"XX check via nslookup"
leaf+"XX confirm port 80"
==
;< ~ bind:m (hall-app-message %dns msg)
loop(ames-domains t.ames-domains)
::
:: +request-by-ip
::
++ request-by-ip
|= if=@if
=/ m (async:stdio ?)
^- form:m
;< good=? bind:m (self-check-http |+if 5)
?. good
:: XX details
~& %bail-early
(pure:m |)
;< ~ bind:m (poke-app:stdio collector-app [%dns-address %if if])
;< our=@p bind:m get-identity:stdio
;< ~ bind:m (peer-app:stdio collector-app /(scot %p our))
(pure:m &)
--
::
=* tapp-async tapp-async:tapp
=* default-tapp default-tapp:tapp
%- create-tapp-all:tapp
^- tapp-core-all:tapp
|_ [=bowl:gall state=app-state]
::
++ handle-init handle-init:default-tapp
++ handle-peek handle-peek:default-tapp
++ handle-peer handle-peer:default-tapp
::
++ handle-poke
|= =in-poke-data
=/ m tapp-async
^- form:m
?. (team:title [our src]:bowl)
~| %configure-yoself !!
?- -.in-poke-data
::
:: "automatic" dns binding -- currently only for galaxies
::
:: XX could be in +handle-init
:: XX use ip reflection for other classes
::
%dns-auto
?. ?=(%czar (clan:title our.bowl))
:: XX details
::
~& %galaxy-only
(pure:m state)
;< ~ bind:m (galaxy-domains ames-domains.in-poke-data)
(pure:m state)
::
:: manual dns binding -- by explicit ipv4
::
%dns-address
=* adr address.in-poke-data
=/ rac (clan:title our.bowl)
?. ?=(?(%king %duke) rac)
~| [%dns-collector-bind-invalid rac] !!
?: (reserved:eyre if.adr)
~| [%dns-collector-reserved-address if.adr] !!
;< requested=? bind:m (request-by-ip if.adr)
:: XX save failure?
=? requested.state requested
(some address.in-poke-data)
(pure:m state)
==
::
++ handle-diff
|= [=dock =path =in-peer-data]
=/ m tapp-async
^- form:m
?. =(dock collector-app)
~| [%unexpected-diff-dock-wat-do dock] !!
?. =(path /(scot %p our.bowl))
~| [%unexpected-diff-path-wat-do path] !!
?- -.in-peer-data
%dns-binding
=* binding binding.in-peer-data
?~ requested.state
~| %unexpected-binding-wat-do !!
?. =(u.requested.state address.binding)
~| %mismatch-binding-wat-do !!
;< good=? bind:m (turf-confirm-install turf.binding)
=/ msg=(pair cord tang)
?: good
[(cat 3 'confirmed access via ' (en-turf:html turf.binding)) ~]
:- (cat 3 'unable to access via ' (en-turf:html turf.binding))
:~ leaf+"XX check via nslookup"
leaf+"XX confirm port 80"
==
;< ~ bind:m (hall-app-message %dns msg)
=? completed.state good (some binding)
:: XX save failure?s
:: XX unsubscribe?
(pure:m state)
==
::
++ handle-take
|= =sign:tapp
=/ m tapp-async
^- form:m
?+ -.sign
~| [%unexpected-sign sign] !!
:: print %poke nacks
::
%coup
?. =(collector-app dock.sign)
(pure:m state)
?~ error.sign
=/ msg=cord
(cat 3 'request for DNS sent to ' (scot %p p:collector-app))
;< ~ bind:m (hall-app-message %dns msg ~)
(pure:m state)
:: XX details
~& %dns-ip-request-failed
%- (slog u.error.sign)
(pure:m state)
:: re-subscribe if (involuntarily) unsubscribed
::
%quit
?. =(path.sign /(scot %p our.bowl))
~| [%unexpected-quit-path-wat-do path.sign] !!
;< ~ bind:m (peer-app:stdio collector-app /(scot %p our.bowl))
(pure:m state)
:: print %peer nacks
::
%reap
?. =(path.sign /(scot %p our.bowl))
~| [%unexpected-reap-path-wat-do path.sign] !!
?~ error.sign
=/ msg=cord
(cat 3 'awaiting response from ' (scot %p p:collector-app))
;< ~ bind:m (hall-app-message %dns msg ~)
(pure:m state)
:: XX details
~& %dns-domain-subscription-failed
%- (slog u.error.sign)
(pure:m state)
==
--

1197
pkg/arvo/app/dojo.hoon Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
:: usage:
:: :eth-manage %look
:: kick polling from eth mainnet node
:: :eth-manage [%wind 1.000.000]
:: rewind to block 1.000.000
=> $~ |%
++ move (pair bone card)
++ card
$% [%turf wire ~]
[%vein wire]
[%look wire src=(each ship purl:eyre)]
[%wind wire p=@ud]
[%snap wire snapshot=snapshot:jael kick=?]
==
++ state
$: a/@
==
--
=, gall
|_ $: hid/bowl
state
==
++ poke
|= [mar=@tas val=*]
^- (quip move _+>)
:_ +>.$
?+ val ~&(%oops ~)
%turf [ost.hid %turf /hi ~]~
%vein [ost.hid %vein /hi]~
[%wind @ud] [ost.hid %wind /hi +.val]~
[%snap * ?]
[ost.hid %snap /hi (snapshot:jael +<.val) +>.val]~
::
%look-ethnode
:_ ~
=/ pul
(need (de-purl:html 'http://eth-mainnet.urbit.org:8545'))
[ost.hid %look /hi |+pul]
::
[%look-kick who=@p]
:_ ~
[ost.hid %look /hi %& who.val]
==
::
++ vein
|= [wir/wire =life ven=(map life ring)]
^- (quip move _+>)
~& [%pierc life ven]
`+>.$
::
++ turf
|= [wir/wire pax=(list path)]
^- (quip move _+>)
~& [%slurp pax]
`+>.$
::
++ prep
|= old/(unit noun)
^- [(list move) _+>.$]
?~ old
`+>.$
=+ new=((soft state) u.old)
?~ new
`+>.$
`+>.$(+<+ u.new)
--

View File

@ -0,0 +1,571 @@
:: watcher: ethereum event log collector
::
/+ *eth-watcher
::
=, ethereum
=, rpc
::
|%
++ state
$: eyes=(map name eye)
==
::
++ eye
$: config
latest-block=@ud
filter-id=@ud
poll-timer=(unit @da)
snapshot
sap=history
==
::
++ history
$: interval=_100
max-count=_10
count=@ud
latest-block=@ud
snaps=(qeu snapshot)
==
::
++ move (pair bone card)
++ card
$% [%hiss wire (unit user:eyre) mark %hiss hiss:eyre]
[%wait wire @da]
[%rest @da]
[%info wire desk nori:clay]
[%diff %eth-watcher-update update]
[%quit ~]
==
--
::
|_ [bowl:gall state]
::
++ prep
|= old=(unit state)
?~ old
[~ ..prep]
[~ ..prep(+<+ u.old)]
::
++ poke-noun
|= [what=?(%save %load) =name]
^- (quip move _+>)
=+ eye=(~(gut by eyes) name *eye)
?- what
%save
=/ pax=path
/(scot %p our)/home/(scot %da now)/watcher/[name]/jam
:_ +>.$
:_ ~
^- move
:* ost
%info
/jamfile
(foal:space:userlib pax [%jam !>((jam eye))])
==
::
%load
=. eyes
%+ ~(put by eyes) name
=- (^eye (cue .^(@ %cx -)))
/(scot %p our)/home/(scot %da now)/watcher/[name]/jam
done:new-filter:(open:watcher name)
==
::
++ poke-eth-watcher-action
|= act=action
^- (quip move _+>)
?- -.act
%watch
done:(init:watcher +.act)
::
%clear
wipe:(open:watcher +.act)
==
::
++ peek-x
|= pax=path
^- (unit (unit [%noun *]))
?. ?=([@ *] pax) ~
=+ eye=(~(get by eyes) i.pax)
?~ eye [~ ~]
:: /name: all logs
::
?~ t.pax ``[%noun logs.u.eye]
:: /name/num: most recent num logs
::
=+ num=(slaw %ud i.t.pax)
?^ num ``[%noun (scag u.num logs.u.eye)]
:: /name/debug: debug information
::
?. ?=(%debug i.t.pax) ~
=- ``[%noun -]
=, u.eye
:* node=(en-purl:html node)
last=last-heard-block
lent=(lent logs)
time=poll-timer
==
::
++ peer
|= pax=path
^- (quip move _+>)
?> ?=([@ ~] pax)
done:(put-snapshot-diff:(open:watcher i.pax) ost)
::
++ wake
|= [wir=wire error=(unit tang)]
^- (quip move _+>)
?^ error
%- (slog u.error)
[~ ..wake]
?> ?=([@ %poll ~] wir)
done:poll-filter:(open:watcher i.wir)
::
++ sigh-tang
|= [wir=wire res=tang]
^- (quip move _+>)
~& ['something went wrong!' wir]
~_ res
[~ +>.$]
::
++ sigh-json-rpc-response
|= [wir=wire res=response:rpc:jstd]
^- (quip move _+>)
?> ?=([@ *] wir)
=< done
%- sigh-json-rpc-response:(open:watcher i.wir)
[t.wir res]
::
++ watcher
|_ $: =name
=eye
rewind-block=(unit @ud)
new-logs=loglist
moves=(list move)
==
::
:: +open: initialize core
::
++ open
|= nom=^name
^+ +>
+>.$(name nom, eye (~(got by eyes) nom))
::
:: +init: set up eye and initialize core
::
++ init
|= [nom=^name =config]
^+ +>
=. name nom
=. eye
%*(. *^eye - config, last-heard-block from-block.config)
get-latest-block
::
:: +| outward
::
:: +wipe: delete eye
::
++ wipe
=> cancel-wait-poll
=> cancel-subscribers
:- (flop moves)
..watcher(eyes (~(del by eyes) name))
::
:: +done: store changes, update subscribers
::
++ done
^- [(list move) _..watcher]
=? . ?=(^ rewind-block)
:: if we're rewinding to a block, then we throw away any moves
:: and changes we were going to make.
::
=: moves *(list move)
new-logs *loglist
==
(restore-block u.rewind-block)
:: if we have any updates, send them
::
=? . !=(~ new-logs)
(fan-diff %logs new-logs)
:: produce moves, store updated state
::
:- (flop moves)
..watcher(eyes (~(put by eyes) name eye))
::
:: +put-move: store side-effect
::
++ put-move
|= =card
%_(+> moves [[ost card] moves])
::
++ put-moves
|= moz=(list move)
%_(+> moves (weld (flop moz) moves))
::
:: +put-rpc-request: store rpc request to ethereum node
::
++ put-rpc-request
|= [wir=wire id=(unit @t) req=request]
^+ +>
%- put-move
^- card
:* %hiss
[name wir]
~
%json-rpc-response
%hiss
%+ json-request node.eye
(request-to-json id req)
==
::
:: +put-log: store change made by event
::
++ put-log
|= log=event-log
%_ +>
new-logs (store-new-logs ~[log] new-logs)
logs.eye (store-new-logs ~[log] logs.eye)
heard.eye (~(put in heard.eye) (log-to-id log))
==
::
:: +| subscriptions
::
++ put-diff
|= [for=bone dif=update]
%_(+> moves [[for %diff %eth-watcher-update dif] moves])
::
++ put-snapshot-diff
|= for=bone
(put-diff for %snap last-heard-block.eye heard.eye logs.eye)
::
++ get-subscribers
^- (list bone)
%+ murn ~(tap by sup)
|= [b=bone s=ship p=path]
^- (unit bone)
?> ?=([@ *] p)
?:(=(name i.p) `b ~)
::
++ fan-diff
|= dif=update
%- put-moves
%+ turn get-subscribers
|= b=bone
^- move
[b %diff %eth-watcher-update dif]
::
++ cancel-subscribers
%- put-moves
%+ turn get-subscribers
|=(b=bone [b %quit ~])
::
:: +| catch-up-operations
::
:: +get-latest-block
::
:: Get latest block from eth node and compare to our own latest block.
:: Get intervening blocks in chunks until we're caught up, then set
:: up a filter going forward.
::
++ get-latest-block
=> cancel-wait-poll
(put-rpc-request /catch-up/block-number `'block number' %eth-block-number ~)
::
:: +catch-up: get next chunk
::
++ catch-up
|= from-block=@ud
^+ +>
?: (gte from-block latest-block.eye)
new-filter
=/ next-block (min latest-block.eye (add from-block 5.760)) :: ~d1
~? debug=|
[%catching-up from=from-block to=latest-block.eye]
%- put-rpc-request
:+ /catch-up/step/(scot %ud from-block)/(scot %ud next-block)
`'catch up'
:* %eth-get-logs
`number+from-block
`number+next-block
contracts.eye
topics.eye
==
::
:: +| filter-operations
::
:: +new-filter: request a new polling filter
::
:: Listens from the last-heard block onward.
::
++ new-filter
%- put-rpc-request
:+ /filter/new `'new filter'
^- request:rpc
:* %eth-new-filter
`number+last-heard-block.eye
?~(to-block.eye ~ `number+u.to-block.eye)
contracts.eye
topics.eye
==
::
:: +read-filter: get all events the filter captures
::
++ read-filter
%- put-rpc-request
:+ /filter/logs `'filter logs'
[%eth-get-filter-logs filter-id.eye]
::
:: +poll-filter: get all new events since last poll (or filter creation)
::
++ poll-filter
?: =(0 filter-id.eye)
~& %no-filter-bad-poll
.
%- put-rpc-request
:+ /filter/changes `'poll filter'
[%eth-get-filter-changes filter-id.eye]
::
:: +wait-poll: remind us to poll in four minutes
::
:: Four minutes because Ethereum RPC filters time out after five.
:: We don't check for an existing timer or clear an old one here,
:: sane flows shouldn't see this being called superfluously.
::
++ wait-poll
=+ wen=(add now ~m4)
%- put-move(poll-timer.eye `wen)
[%wait name^/poll wen]
::
:: +cancel-wait-poll: remove poll reminder
::
++ cancel-wait-poll
?~ poll-timer.eye ..cancel-wait-poll
%- put-move(poll-timer.eye ~)
[%rest u.poll-timer.eye]
::
:: +| filter-results
::
:: +sigh-json-rpc-response: process rpc response
::
++ sigh-json-rpc-response
|= [wir=wire res=response:rpc:jstd]
^+ +>
~! -.res
?: ?=(%fail -.res)
?: =(405 p.hit.res)
~& 'HTTP 405 error (expected if using infura)'
+>.$
?. =(5 (div p.hit.res 100))
~& [%http-error hit.res]
+>.$
?+ wir
~& [%retrying-node ~] ::((soft tang) q.res)]
wait-poll
[%catch-up %step @ta @ta ~]
~& %retrying-catch-up
(catch-up (slav %ud `@ta`i.t.t.wir))
==
?+ wir ~|([%weird-sigh-wire wir] !!)
[%filter %new *]
(take-new-filter res)
::
[%filter *]
(take-filter-results res)
::
[%catch-up %block-number ~]
(take-block-number res)
::
[%catch-up %step @ta @ta ~]
=/ from-block (slav %ud `@ta`i.t.t.wir)
=/ next-block (slav %ud `@ta`i.t.t.t.wir)
(take-catch-up-step res from-block next-block)
==
::
:: +take-new-filter: store filter-id and read it
::
++ take-new-filter
|= rep=response:rpc:jstd
^+ +>
~| rep
?< ?=(%batch -.rep)
?< ?=(%fail -.rep)
?: ?=(%error -.rep)
~& [%filter-error--retrying message.rep]
new-filter
=- read-filter(filter-id.eye -)
(parse-eth-new-filter-res res.rep)
::
:: +take-filter-results: parse results into event-logs and process them
::
++ take-filter-results
|= rep=response:rpc:jstd
^+ +>
?< ?=(%batch -.rep)
?< ?=(%fail -.rep)
?: ?=(%error -.rep)
?. ?| =('filter not found' message.rep) :: geth
=('Filter not found' message.rep) :: parity
==
~& [%unhandled-filter-error +.rep]
+>
~& [%filter-timed-out--recreating block=last-heard-block.eye +.rep]
:: arguably should rewind 40 blocks on the off chance the chain reorganized
:: when we blinked. this will also restart the filter.
::
:: (restore-block ?:((lth last-heard-block 40) 0 (sub.add last-heard-block 40)))
::
:: counter-argument: it's a royal pain to restore from a snapshot
:: every time you can't ping the node for 5 minutes. this is likely
:: to destabilize the network. better to manually restore if we
:: notice an anomaly.
::
:: third way: don't trust anything that doesn't have 40 confirmations
::
new-filter
:: kick polling timer, only if it hasn't already been.
=? +> |(?=(~ poll-timer.eye) (gth now u.poll-timer.eye))
wait-poll
(take-events rep)
::
:: +take-block-number: take block number and start catching up
::
++ take-block-number
|= rep=response:rpc:jstd
^+ +>
?< ?=(%batch -.rep)
?< ?=(%fail -.rep)
?: ?=(%error -.rep)
~& [%take-block-number-error--retrying message.rep]
get-latest-block
=. latest-block.eye (parse-eth-block-number res.rep)
(catch-up last-heard-block.eye)
::
:: +take-catch-up-step: process chunk
::
++ take-catch-up-step
|= [rep=response:rpc:jstd from-block=@ud next-block=@ud]
^+ +>
?< ?=(%batch -.rep)
?< ?=(%fail -.rep)
?: ?=(%error -.rep)
~& [%catch-up-step-error--retrying message.rep]
(catch-up from-block)
=. +>.$ (take-events rep)
(catch-up next-block)
::
:: +take-events: process events
::
++ take-events
|= rep=response:rpc:jstd
^+ +>
?< ?=(%batch -.rep)
?< ?=(%fail -.rep)
?< ?=(%error -.rep)
?. ?=(%a -.res.rep)
~& [%events-not-array rep]
!!
=* changes p.res.rep
~? &(debug=| (gth (lent changes) 0))
:* %processing-changes
changes=(lent changes)
block=last-heard-block.eye
id=filter-id.eye
==
|- ^+ +>.^$
?~ changes +>.^$
=. +>.^$
(take-event-log (parse-event-log i.changes))
$(changes t.changes)
::
:: +take-event-log: obtain changes from event-log
::
++ take-event-log
|= log=event-log
^+ +>
?~ mined.log
~& %ignoring-unmined-event
+>
=* place u.mined.log
?: (~(has in heard.eye) block-number.place log-index.place)
?. removed.u.mined.log
~? debug=|
[%ignoring-duplicate-event tx=transaction-hash.u.mined.log]
+>
:: block was reorganized away, so rewind to this block and
:: start syncing again.
::
~& :* 'removed event! Perhaps chain has reorganized?'
tx-hash=transaction-hash.u.mined.log
block-number=block-number.u.mined.log
block-hash=block-hash.u.mined.log
==
%= +>
rewind-block
:- ~
?~ rewind-block
block-number.place
(min block-number.place u.rewind-block)
==
=. last-heard-block.eye
(max block-number.place last-heard-block.eye)
?: ?& (gte block-number.place from-block.eye)
?| ?=(~ to-block.eye)
(lte block-number.place u.to-block.eye)
==
==
(put-log log)
~& :* %event-block-out-of-range
got=block-number.place
from=from-block.eye
to=to-block.eye
==
+>.$
::
:: +restore-block: rewind to block or earlier
::
++ restore-block
|= block=@ud
^+ +>
=/ old-qeu snaps.sap.eye
:: clear history
::
=: snaps.sap.eye ~
count.sap.eye 0
latest-block.sap.eye 0
==
:: find a snapshot we can use, remove ones that are too new
::
=^ snap=snapshot +>.$
?: |(=(~ old-qeu) (lth block last-heard-block:(need ~(top to old-qeu))))
[%*(. *snapshot last-heard-block from-block.eye) +>.$]
|- ^- [snapshot _+>.^$]
=^ snap=snapshot old-qeu
~(get to old-qeu)
=: count.sap.eye +(count.sap.eye)
latest-block.sap.eye last-heard-block.snap
snaps.sap.eye (~(put to snaps.sap.eye) snap)
==
?: |(=(~ old-qeu) (lth block last-heard-block:(need ~(top to old-qeu))))
[snap +>.^$]
$
~& [%restoring-block block last-heard-block.snap]
(restore-snap snap)
::
:: +restore-snap: revert state to snapshot
::
++ restore-snap
|= snap=snapshot
^+ +>
:: notify subscribers
::TODO be more nuanced about what changed, maybe
::
=. +>.$ (fan-diff snap+snap)
:: restore state and kick new fetch cycle
::
%= get-latest-block
last-heard-block.eye last-heard-block.snap
heard.eye heard.snap
logs.eye logs.snap
==
--
--

View File

@ -0,0 +1,147 @@
:: Little app to demonstrate the structure of programs written with the
:: transaction monad.
::
:: Fetches the top comment of each of the top 10 stories from Hacker News
::
/+ tapp, stdio
::
:: Preamble
::
=>
|%
+$ state
$: top-comments=(list tape)
==
+$ peek-data _!!
+$ in-poke-data [%noun =cord]
+$ out-poke-data ~
+$ in-peer-data ~
+$ out-peer-data
$% [%comments (list tape)]
==
++ tapp (^tapp state peek-data in-poke-data out-poke-data in-peer-data out-peer-data)
++ stdio (^stdio out-poke-data out-peer-data)
--
=>
|%
:: Helper function to print a comment
::
++ comment-to-tang
|= =tape
^- tang
%+ welp
%+ turn (rip 10 (crip tape))
|= line=cord
leaf+(trip line)
[leaf+""]~
::
:: All the URLs we fetch from
::
++ urls
=/ base "https://hacker-news.firebaseio.com/v0/"
:* top-stories=(weld base "topstories.json")
item=|=(item=@ud `tape`:(welp base "item/" +>:(scow %ui item) ".json"))
==
--
=, async=async:tapp
=, tapp-async=tapp-async:tapp
=, stdio
::
:: The app
::
%- create-tapp-poke-peer-take:tapp
^- tapp-core-poke-peer-take:tapp
|_ [=bowl:gall state]
::
:: Main function
::
++ handle-poke
|= =in-poke-data
=/ m tapp-async
^- form:m
::
:: If requested to print, just print what we have in our state
::
?: =(cord.in-poke-data 'print')
~& 'drumroll please...'
;< now=@da bind:m get-time
;< ~ bind:m (wait (add now ~s3))
~& 'Top comments:'
%- (slog (zing (turn top-comments comment-to-tang)))
(pure:m top-comments)
?: =(cord.in-poke-data 'poll')
;< ~ bind:m (wait-effect (add now.bowl ~s15))
(pure:m top-comments)
::
:: Otherwise, fetch the top HN stories
::
=. top-comments ~
::
:: If this whole thing takes more than 15 seconds, cancel it
::
%+ (set-timeout _top-comments) (add now.bowl ~s15)
;< =top-stories=json bind:m (fetch-json top-stories:urls)
=/ top-stories=(list @ud)
((ar ni):dejs:format top-stories-json)
::
:: Loop through the first 5 stories
::
=. top-stories (scag 5 top-stories)
|- ^- form:m
=* loop $
::
:: If done, tell subscribers and print the results
::
?~ top-stories
;< ~ bind:m (give-result /comments %comments top-comments)
(handle-poke %noun 'print')
::
:: Else, fetch the story info
::
~& "fetching item #{+>:(scow %ui i.top-stories)}"
;< =story-info=json bind:m (fetch-json (item:urls i.top-stories))
=/ story-comments=(unit (list @ud))
((ot kids+(ar ni) ~):dejs-soft:format story-info-json)
::
:: If no comments, say so
::
?: |(?=(~ story-comments) ?=(~ u.story-comments))
=. top-comments ["<no top comment>" top-comments]
loop(top-stories t.top-stories)
::
:: Else, fetch comment info
::
;< =comment-info=json bind:m (fetch-json (item:urls i.u.story-comments))
=/ comment-text=(unit tape)
((ot text+sa ~):dejs-soft:format comment-info-json)
::
:: If no text (eg comment deleted), record that
::
?~ comment-text
=. top-comments ["<top comment has no text>" top-comments]
loop(top-stories t.top-stories)
::
:: Else, add text to state
::
=. top-comments [u.comment-text top-comments]
loop(top-stories t.top-stories)
::
++ handle-peer
|= =path
=/ m tapp-async
^- form:m
~& [%tapp-fetch-take-peer path]
(pure:m top-comments)
::
++ handle-take
|= =sign:tapp
=/ m tapp-async
^- form:m
:: ignore %poke/peer acknowledgements
::
?. ?=(%wake -.sign)
(pure:m top-comments)
;< =state bind:m (handle-poke %noun 'fetch')
=. top-comments state
(pure:m top-comments)
--

View File

@ -0,0 +1,50 @@
/+ tapp, stdio
=>
|%
+$ subscription-state
$: target=[her=ship app=term]
=path
==
+$ state
$: subscription=(unit subscription-state)
==
+$ peek-data _!!
+$ in-poke-data [%noun =cord]
+$ out-poke-data [%noun =cord]
+$ out-peer-data ~
+$ in-peer-data
$% [%comments comments=(list tape)]
==
++ tapp (^tapp state peek-data in-poke-data out-poke-data in-peer-data out-peer-data)
++ stdio (^stdio out-poke-data out-peer-data)
--
=, async=async:tapp
=, tapp-async=tapp-async:tapp
=, stdio
%- create-tapp-poke-diff:tapp
^- tapp-core-poke-diff:tapp
|_ [=bowl:gall state]
++ handle-poke
|= =in-poke-data
=/ m tapp-async
^- form:m
?: =(cord.in-poke-data 'pull')
?~ subscription
(async-fail %no-subscription ~)
;< ~ bind:m (pull-app [target path]:u.subscription)
(pure:m ~)
=/ target [our.bowl %example-tapp-fetch]
;< ~ bind:m (poke-app target %noun 'print')
;< ~ bind:m (peer-app target /comments)
=. subscription `[target /comments]
;< ~ bind:m (wait (add now.bowl ~s3))
(pure:m subscription)
::
++ handle-diff
|= [[her=ship app=term] =path data=in-peer-data]
=/ m tapp-async
^- form:m
?> ?=(%comments -.data)
~& subscriber-got-data=(lent comments.data)
(pure:m subscription)
--

490
pkg/arvo/app/gaze.hoon Normal file
View File

@ -0,0 +1,490 @@
:: gaze: azimuth statistics
::
/+ *eth-watcher
::
=, ethereum
=, azimuth
::
|%
++ state
$: :: qued: event logs waiting on block timestamp, oldest first
:: time: timstamps of block numbers
:: seen: events sorted by timestamp, newest first
:: days: stats by day, newest first
::
qued=loglist
time=(map @ud @da)
seen=(list [wen=@da wat=event])
days=(list [day=@da sat=stats])
==
::
++ event
$% [%azimuth who=ship dif=diff-point]
::TODO [%invites *]
==
::
++ stats
$: spawned=(list @p)
activated=(list @p)
transfer-p=(list @p)
transferred=(list @p)
configured=(list @p)
breached=(list @p)
request=(list @p)
sponsor=(list @p)
management-p=(list @p)
voting-p=(list @p)
spawn-p=(list @p)
==
::
::
++ move (pair bone card)
++ card
$% [%poke wire [ship %eth-watcher] %eth-watcher-action action]
[%peer wire [ship %eth-watcher] path]
[%hiss wire (unit user:eyre) mark %hiss hiss:eyre]
[%wait wire @da]
[%info wire desk nori:clay]
==
--
::
|_ [bowl:gall state]
++ node-url (need (de-purl:html 'http://eth-mainnet.urbit.org:8545'))
++ export-frequency ~h1
::
++ prep
|= old=(unit state)
?~ old
:_ ..prep
[ost %wait /export (add now export-frequency)]~
[~ ..prep(+<+ u.old)]
::
:: +poke-noun: do a thing
::
:: %kick-watcher: reset, tell %eth-watcher to look for events for us
:: %regaze: reset (but keep timestamps), subscribe to eth-watcher
:: %debug: print debug info
::
++ poke-noun
|= a=?(%kick-watcher %regaze %debug)
^- (quip move _+>)
?- a
%kick-watcher
:_ +>.$(qued ~, seen ~, days ~, time ~)
:~
:- ost
:* %poke
/look
[our %eth-watcher]
%eth-watcher-action
::
^- action
:+ %watch dap
:* node-url
public:contracts
~
~[azimuth:contracts]
~
==
==
==
::
%regaze
:_ +>.$(qued ~, seen ~, days ~)
:~
:- ost
:* %peer
/look
[our %eth-watcher]
/[dap]
==
==
::
%debug
~& latest=(turn (scag 5 seen) head)
~& oldest=(turn (slag (sub (lent seen) 5) seen) head)
~& :- 'order is'
=- ?:(sane 'sane' 'insane')
%+ roll seen
|= [[this=@da *] last=@da sane=?]
:- this
?: =(*@da last) &
(lte this last)
~& time=~(wyt by time)
~& qued=(lent qued)
~& days=(lent days)
[~ +>.$]
==
::
:: +diff-eth-watcher-update: process new logs, clear state on rollback
::
++ diff-eth-watcher-update
|= [=wire =^update]
^- (quip move _+>)
=^ logs +>.$
?- -.update
%snap ~& [%got-snap (lent logs.snapshot.update)]
[logs.snapshot.update +>.$(qued ~, seen ~)]
%logs ~& [%got-logs (lent loglist.update)]
[loglist.update +>.$]
==
?~ logs [~ +>.$]
=- =^ moz +>.$ (queue-logs mistime) :: oldest first
=. +>.$ (process-logs havtime) :: oldest first
[moz +>.$]
:: sort based on timstamp known, throw out lockup logs
::
%+ roll `loglist`logs
|= [log=event-log:rpc havtime=loglist mistime=loglist]
^+ [havtime mistime]
=+ bon=block-number:(need mined.log)
?: (is-lockup-block bon) [havtime mistime]
?: (~(has by time) bon)
[[log havtime] mistime]
[havtime [log mistime]]
::
:: +is-lockup-block: whether the block contains lockup/ignorable transactions
::
:: this is the stupid dumb equivalent to actually identifying lockup
:: transactions procedurally, which is still in git history, but didn't
:: work quite right for unidentified reasons
::
++ is-lockup-block
|= num=@ud
^- ?
%+ roll
^- (list [@ud @ud])
:~ [7.050.978 7.051.038]
==
|= [[start=@ud end=@ud] in=_|]
?: in &
&((gte num start) (lte num end))
::
:: +queue-logs: hold on to new logs, requesting timestamps for them
::
++ queue-logs
|= logs=loglist :: oldest first
^- (quip move _+>)
?~ logs [~ +>]
:- [(request-timestamps logs) ~]
+>(qued (weld qued logs))
::
:: +request-timestamps: request block timestamps for the logs as necessary
::
++ request-timestamps
|= logs=loglist
^- move
=- [ost %hiss /timestamps ~ %json-rpc-response %hiss -]
^- hiss:eyre
%+ json-request:rpc node-url
:- %a
^- (list json)
%+ turn
^- (list @ud)
=- ~(tap in -)
%- ~(gas in *(set @ud))
^- (list @ud)
%+ turn logs
|= log=event-log:rpc
block-number:(need mined.log)
|= num=@ud
^- json
~! *request:rpc
%+ request-to-json:rpc
`(scot %ud num)
[%eth-get-block-by-number num |]
::
:: +sigh-json-rpc-response: get block details, extract timestamps
::
++ sigh-json-rpc-response
|= [=wire =response:rpc:jstd]
^- (quip move _+>)
?> ?=([%timestamps ~] wire)
?: ?=(?(%error %fail) -.response)
~? ?=(%error -.response) [%rpc-error +.response]
~? ?=(%fail -.response) [%httr-fail hit.response]
~& %retrying-timestamps
[[(request-timestamps qued) ~] +>]
?> ?=(%batch -.response)
=- [~ (process-logs(time -, qued ~) qued)]
%- ~(gas by time)
=/ max=@ud
(roll ~(tap in ~(key by time)) max)
:: for every result, get the block number and timestamp
::
%+ turn bas.response
|= res=response:rpc:jstd
^- (pair @ud @da)
~| res
?> ?=(%result -.res)
~| id.res
:- (slav %ud id.res)
%- from-unix:chrono:userlib
%- parse-hex-result:rpc
?> ?=(%o -.res.res)
(~(got by p.res.res) 'timestamp')
::
:: +process logs that are in the queue
::
++ process-logs
|= logs=loglist :: oldest first
^+ +>
?~ logs +>
=- %_ +>.$
qued (flop rest) :: oldest first
seen (weld logs seen) :: newest first
days (count-events (flop logs)) :: oldest first
==
%+ roll `loglist`logs
|= [log=event-log:rpc rest=loglist logs=(list [wen=@da wat=event])]
:: to ensure logs are processed in sane order,
:: stop processing as soon as we skipped one
::
?^ rest [[log rest] logs]
=/ tim=(unit @da)
%- ~(get by time)
block-number:(need mined.log)
?~ tim [[log rest] logs]
:- rest
=+ ven=(event-log-to-event log)
?~ ven logs
[[u.tim u.ven] logs]
::
:: +event-log-to-event: turn raw log into gaze noun
::
++ event-log-to-event
|= log=event-log:rpc
^- (unit event)
?: =(azimuth:contracts address.log)
=+ (event-log-to-point-diff log)
?~ - ~
`azimuth+u
::TODO delegated sending support
~
::
:: +count-events: add events to the daily stats
::
++ count-events
|= logs=_seen :: oldest first
^+ days
=/ head=[day=@da sat=stats]
?^ days i.days
*[@da stats]
=+ tail=?~(days ~ t.days)
|-
:: when done, store updated head, but only if it's set
::
?~ logs
?: =(*[@da stats] head) tail
[head tail]
=* log i.logs
:: calculate day for current event, set head if unset
::
=/ day=@da
(sub wen.log (mod wen.log ~d1))
=? day.head =(*@da day.head) day
:: same day as head, so add to it
::
?: =(day day.head)
%_ $
sat.head (count-event wat.log sat.head)
logs t.logs
==
~| [%weird-new-day old=day.head new=day]
?> (gth day day.head)
:: newer day than head of days, so start new head
::
%_ $
tail [head tail]
head [day *stats]
==
::
:: +count-event: add event to the stats, if it's relevant
::
++ count-event
|= [eve=event sat=stats]
^- stats
?> ?=(%azimuth -.eve)
?+ -.dif.eve sat
%spawned sat(spawned [who.dif.eve spawned.sat])
%activated sat(activated [who.eve activated.sat])
%transfer-proxy ?: =(0x0 new.dif.eve) sat
sat(transfer-p [who.eve transfer-p.sat])
%owner sat(transferred [who.eve transferred.sat])
%keys sat(configured [who.eve configured.sat])
%continuity sat(breached [who.eve breached.sat])
%escape ?~ new.dif.eve sat
sat(request [who.eve request.sat])
%sponsor ?. has.new.dif.eve sat
sat(sponsor [who.eve sponsor.sat])
%management-proxy sat(management-p [who.eve management-p.sat])
%voting-proxy sat(voting-p [who.eve voting-p.sat])
%spawn-proxy sat(spawn-p [who.eve spawn-p.sat])
==
::
::
:: +wake-export: periodically export data
::
++ wake-export
|= [=wire ~]
^- (quip move _+>)
:_ +>
:~ [ost %wait /export (add now export-frequency)]
(export-move %days (export-days days))
(export-move %months (export-months days))
(export-move %events export-raw)
==
::
:: +export-move: %info move to write exported .txt
::
++ export-move
|= [nom=@t dat=(list @t)]
^- move
:^ ost %info /export/[nom]
%+ foal:space:userlib
/(scot %p our)/home/(scot %da now)/gaze-exports/[nom]/txt
[%txt !>(dat)]
::
:: +peek-x: accept gall scry
::
:: %/days/txt: per day, digest stats
:: %/months/txt: per month, digest stats
:: %/raw/txt: all observed events
::
++ peek-x
|= pax=path
^- (unit (unit (pair mark *)))
?~ pax ~
?: =(%days i.pax)
:^ ~ ~ %txt
(export-days days)
?: =(%months i.pax)
:^ ~ ~ %txt
(export-months days)
?: =(%raw i.pax)
``txt+export-raw
~
::
:: +export-months: generate a csv of stats per month
::
++ export-months
|= =_days
%- export-days
^+ days
%+ roll (flop days)
|= [[day=@da sat=stats] mos=(list [mod=@da sat=stats])]
^+ mos
=/ mod=@da
%- year
=+ (yore day)
-(d.t 1)
?~ mos [mod sat]~
?: !=(mod mod.i.mos)
[[mod sat] mos]
:_ t.mos
:- mod
::TODO this is hideous. can we make a wet gate do this?
:* (weld spawned.sat spawned.sat.i.mos)
(weld activated.sat activated.sat.i.mos)
(weld transfer-p.sat transfer-p.sat.i.mos)
(weld transferred.sat transferred.sat.i.mos)
(weld configured.sat configured.sat.i.mos)
(weld breached.sat breached.sat.i.mos)
(weld request.sat request.sat.i.mos)
(weld sponsor.sat sponsor.sat.i.mos)
(weld management-p.sat management-p.sat.i.mos)
(weld voting-p.sat voting-p.sat.i.mos)
(weld spawn-p.sat spawn-p.sat.i.mos)
==
::
:: +export-days: generate a csv of stats per day
::
++ export-days
|= =_days
:- %- crip
;: weld
"date,"
"spawned,"
"activated,"
"transfer proxy,"
"transferred,"
"transferred (unique),"
"configured,"
"configured (unique),"
"escape request,"
"sponsor change"
==
|^ ^- (list @t)
%+ turn days
|= [day=@da stats]
%- crip
;: weld
(scow %da day) ","
(count spawned) ","
(count activated) ","
(count transfer-p) ","
(unique transferred) ","
(unique configured) ","
(count request) ","
(count sponsor)
==
::
++ count
|* l=(list)
(num (lent l))
::
++ unique
|* l=(list)
;: weld
(count l)
","
(num ~(wyt in (~(gas in *(set)) l)))
==
::
++ num (d-co:co 1)
--
::
:: +export-raw: generate a csv of individual transactions
::
++ export-raw
:- %- crip
;: weld
"date,"
"point,"
"event,"
"field 1"
==
|^ ^- (list @t)
%+ turn seen
|= [wen=@da wat=event]
%- crip
;: weld
(scow %da wen) ","
(pon who.wat) ","
(point-diff-to-row dif.wat)
==
::
++ point-diff-to-row
|= dif=diff-point
?- -.dif
%full "full,"
%owner "owner,{(adr new.dif)}"
%activated "activated,"
%spawned "spawned,{(pon who.dif)}"
%keys "keys,{(num life.dif)}"
%continuity "breached,{(num new.dif)}"
%sponsor "sponsor,{(spo has.new.dif)} {(pon who.new.dif)}"
%escape "escape-req,{(req new.dif)}"
%management-proxy "management-p,{(adr new.dif)}"
%voting-proxy "voting-p,{(adr new.dif)}"
%spawn-proxy "spawn-p,{(adr new.dif)}"
%transfer-proxy "transfer-p,{(adr new.dif)}"
==
::
++ num (d-co:co 1)
++ pon (cury scow %p)
++ adr |=(a=@ ['0' 'x' ((x-co:co (mul 2 20)) a)])
++ spo |=(h=? ?:(h "escaped to" "detached from"))
++ req |=(r=(unit @p) ?~(r "canceled" (pon u.r)))
--
--

3354
pkg/arvo/app/hall.hoon Normal file

File diff suppressed because it is too large Load Diff

200
pkg/arvo/app/hood.hoon Normal file
View File

@ -0,0 +1,200 @@
:: :: ::
:::: /hoon/hood/app :: ::
:: :: ::
/? 310 :: zuse version
/+ sole, :: libraries
:: XX these should really be separate apps, as
:: none of them interact with each other in
:: any fashion; however, to reduce boot-time
:: complexity and work around the current
:: non-functionality of end-to-end acknowledgments,
:: they have been bundled into :hood
::
:: |command handlers
hood-helm, hood-kiln, hood-drum, hood-write
:: :: ::
:::: :: ::
:: :: ::
|%
++ hood-module
:: each hood module follows this general shape
=> |%
+$ part [%module %0 pith]
+$ pith ~
::
+$ move [bone card]
+$ card $% [%fake ~]
==
--
|= [bowl:gall own=part]
|_ moz=(list move)
++ abet [(flop moz) own]
--
--
:: :: ::
:::: :: :: state handling
:: :: ::
!:
=> |% ::
++ hood-old :: unified old-state
{?($0 $1) lac/(map @tas hood-part-old)} ::
++ hood-1 :: unified state
{$1 lac/(map @tas hood-part)} ::
++ hood-good :: extract specific
=+ hed=$:hood-head
|@ ++ $
|: paw=$:hood-part
?- hed
$drum ?>(?=($drum -.paw) `part:hood-drum`paw)
$helm ?>(?=($helm -.paw) `part:hood-helm`paw)
$kiln ?>(?=($kiln -.paw) `part:hood-kiln`paw)
$write ?>(?=($write -.paw) `part:hood-write`paw)
==
--
++ hood-head _-:$:hood-part :: initialize state
++ hood-make ::
=+ $:{our/@p hed/hood-head} ::
|@ ++ $
?- hed
$drum (make:hood-drum our)
$helm *part:hood-helm
$kiln *part:hood-kiln
$write *part:hood-write
==
--
++ hood-part-old hood-part :: old state for ++prep
++ hood-port :: state transition
|: paw=$:hood-part-old ^- hood-part ::
paw ::
:: ::
++ hood-part :: current module state
$% {$drum $2 pith-2:hood-drum} ::
{$helm $0 pith:hood-helm} ::
{$kiln $0 pith:hood-kiln} ::
{$write $0 pith:hood-write} ::
== ::
-- ::
:: :: ::
:::: :: :: app proper
:: :: ::
=, gall
|_ $: hid/bowl :: gall environment
hood-1 :: module states
== ::
++ able :: find+make part
=+ hed=$:hood-head
|@ ++ $
=+ rep=(~(get by lac) hed)
=+ par=?^(rep u.rep `hood-part`(hood-make our.hid hed))
((hood-good hed) par)
--
::
++ ably :: save part
=+ $:{(list) hood-part}
|@ ++ $
[(flop +<-) %_(+> lac (~(put by lac) +<+< +<+))]
--
:: :: ::
:::: :: :: generic handling
:: :: ::
++ prep
|= old/(unit hood-old) ^- (quip _!! _+>)
:- ~
?~ old +>
+>(lac (~(run by lac.u.old) hood-port))
::
++ poke-hood-load :: recover lost brain
|= dat/hood-part
?> =(our.hid src.hid)
~& loaded+-.dat
[~ %_(+> lac (~(put by lac) -.dat dat))]
::
::
++ from-module :: create wrapper
|* _[identity=%module start=..$ finish=_abet]:(hood-module)
=- [wrap=- *start] :: usage (wrap handle-arm):from-foo
|* handle/_finish
|= a=_+<.handle
=. +>.handle (start hid (able identity))
(ably (handle a))
::
:: per-module interface wrappers
++ from-drum (from-module %drum [..$ _se-abet]:(hood-drum))
++ from-helm (from-module %helm [..$ _abet]:(hood-helm))
++ from-kiln (from-module %kiln [..$ _abet]:(hood-kiln))
++ from-write (from-module %write [..$ _abet]:(hood-write))
::
:: :: ::
:::: :: :: switchboard
:: :: ::
++ coup-drum-phat (wrap take-coup-phat):from-drum
++ coup-helm-hi (wrap coup-hi):from-helm
++ coup-kiln-fancy (wrap take-coup-fancy):from-kiln
++ coup-kiln-reload (wrap take-coup-reload):from-kiln
++ coup-kiln-spam (wrap take-coup-spam):from-kiln
++ diff-sole-effect-drum-phat (wrap diff-sole-effect-phat):from-drum
++ init-helm |=({way/wire *} [~ +>])
++ mack-kiln (wrap mack):from-kiln
++ made-write (wrap made):from-write
++ made-kiln (wrap take-made):from-kiln
++ mere-kiln (wrap take-mere):from-kiln
++ mere-kiln-sync (wrap take-mere-sync):from-kiln
++ wake-kiln-overload (wrap take-wake-overload):from-kiln
++ wake-helm-automass (wrap take-wake-automass):from-helm
++ onto-drum (wrap take-onto):from-drum
++ peer-drum (wrap peer):from-drum
++ poke-atom (wrap poke-atom):from-helm
++ poke-dill-belt (wrap poke-dill-belt):from-drum
++ poke-dill-blit (wrap poke-dill-blit):from-drum
++ poke-drum-put (wrap poke-put):from-drum
++ poke-drum-link (wrap poke-link):from-drum
++ poke-drum-unlink (wrap poke-unlink):from-drum
++ poke-drum-exit (wrap poke-exit):from-drum
++ poke-drum-start (wrap poke-start):from-drum
++ poke-helm-hi (wrap poke-hi):from-helm
::++ poke-helm-invite (wrap poke-invite):from-helm
++ poke-helm-mass (wrap poke-mass):from-helm
++ poke-helm-reload (wrap poke-reload):from-helm
++ poke-helm-reload-desk (wrap poke-reload-desk):from-helm
++ poke-helm-reset (wrap poke-reset):from-helm
++ poke-helm-serve (wrap poke-serve):from-helm
++ poke-helm-send-hi (wrap poke-send-hi):from-helm
++ poke-helm-verb (wrap poke-verb):from-helm
++ poke-helm-rekey (wrap poke-rekey):from-helm
++ poke-helm-nuke (wrap poke-nuke):from-helm
++ poke-helm-automass (wrap poke-automass):from-helm
++ poke-helm-cancel-automass (wrap poke-cancel-automass):from-helm
++ poke-helm-bonk (wrap poke-bonk):from-helm
++ poke-hood-sync (wrap poke-sync):from-kiln
++ poke-kiln-commit (wrap poke-commit):from-kiln
++ poke-kiln-info (wrap poke-info):from-kiln
++ poke-kiln-label (wrap poke-label):from-kiln
++ poke-kiln-merge (wrap poke-merge):from-kiln
++ poke-kiln-cancel (wrap poke-cancel):from-kiln
++ poke-kiln-mount (wrap poke-mount):from-kiln
++ poke-kiln-rm (wrap poke-rm):from-kiln
++ poke-kiln-schedule (wrap poke-schedule):from-kiln
++ poke-kiln-track (wrap poke-track):from-kiln
++ poke-kiln-sync (wrap poke-sync):from-kiln
++ poke-kiln-syncs (wrap poke-syncs):from-kiln
++ poke-kiln-start-autoload (wrap poke-start-autoload):from-kiln
++ poke-kiln-wipe-ford (wrap poke-wipe-ford):from-kiln
++ poke-kiln-keep-ford (wrap poke-keep-ford):from-kiln
++ poke-kiln-autoload (wrap poke-autoload):from-kiln
++ poke-kiln-overload (wrap poke-overload):from-kiln
++ poke-kiln-unmount (wrap poke-unmount):from-kiln
++ poke-kiln-unsync (wrap poke-unsync):from-kiln
++ poke-kiln-permission (wrap poke-permission):from-kiln
++ poke-write-sec-atom (wrap poke-sec-atom):from-write
++ poke-write-paste (wrap poke-paste):from-write
++ poke-write-tree (wrap poke-tree):from-write
++ poke-write-wipe (wrap poke-wipe):from-write
++ quit-drum-phat (wrap quit-phat):from-drum
++ reap-drum-phat (wrap reap-phat):from-drum
++ woot-helm (wrap take-woot):from-helm
++ writ-kiln-autoload (wrap take-writ-autoload):from-kiln
++ writ-kiln-find-ship (wrap take-writ-find-ship):from-kiln
++ writ-kiln-sync (wrap take-writ-sync):from-kiln
++ bound (wrap take-bound):from-helm
--

133
pkg/arvo/app/launch.hoon Normal file
View File

@ -0,0 +1,133 @@
/+ *server, launch
/= index
/^ $-(marl manx)
/: /===/app/launch/index /!noun/
/= script
/^ octs
/; as-octs:mimes:html
/: /===/app/launch/js/index
/| /js/
/~ ~
==
/= style
/^ octs
/; as-octs:mimes:html
/: /===/app/launch/css/index
/| /css/
/~ ~
==
/= launch-png
/^ (map knot @)
/: /===/app/launch/img /_ /png/
::
=, launch
::
|_ [bol=bowl:gall sta=state]
::
++ this .
::
++ prep
|= old=(unit state)
^- (quip move _this)
?~ old
:_ this
[ost.bol %connect / [~ /] %launch]~
[~ this(sta u.old)]
::
++ poke-launch-action
|= act=action:launch
^- (quip move _this)
=/ beforedata (~(get by data.sta) name.act)
=/ newdata
?~ beforedata
(~(put by data.sta) name.act [*json url.act])
(~(put by data.sta) name.act [jon.u.beforedata url.act])
:- [ost.bol %peer subscribe.act [our.bol name.act] subscribe.act]~
%= this
tiles.sta (~(put in tiles.sta) [name.act subscribe.act])
data.sta newdata
path-to-tile.sta (~(put by path-to-tile.sta) subscribe.act name.act)
==
::
++ peer-main
|= [pax=path]
^- (quip move _this)
=/ data/json
%- pairs:enjs:format
%+ turn ~(tap by data.sta)
|= [key=@tas [jon=json url=@t]]
[key jon]
:_ this
[ost.bol %diff %json data]~
::
++ diff-json
|= [pax=path jon=json]
^- (quip move _this)
=/ name/@tas (~(got by path-to-tile.sta) pax)
=/ data/(unit [json url=@t]) (~(get by data.sta) name)
?~ data
[~ this]
::
:-
%+ turn (prey:pubsub:userlib /main bol)
|= [=bone *]
[bone %diff %json (frond:enjs:format name jon)]
::
%= this
data.sta (~(put by data.sta) name [jon url.u.data])
==
::
++ generate-script-marl
|= data=tile-data
^- marl
%+ turn ~(tap by data)
|= [key=@tas [jon=json url=@t]]
^- manx
;script@"{(trip url)}";
::
++ 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
=/ site (flop site.request-line)
?~ site
=/ hym=manx (index (generate-script-marl data.sta))
:_ this
[ost.bol %http-response (manx-response:app hym)]~
?+ site.request-line
:_ this
[ost.bol %http-response not-found:app]~
::
:: styling
::
[%'~launch' %css %index ~]
:_ this
[ost.bol %http-response (css-response:app style)]~
::
:: javascript
::
[%'~launch' %js %index ~]
:_ this
[ost.bol %http-response (js-response:app script)]~
::
:: images
::
[%'~launch' %img *]
=/ img (as-octs:mimes:html (~(got by launch-png) `@ta`name))
:_ this
[ost.bol %http-response (png-response:app img)]~
==
::
++ bound
|= [wir=wire success=? binding=binding:eyre]
^- (quip move _this)
[~ this]
::
--

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

View File

@ -0,0 +1,18 @@
|= scripts=marl
;html
;head
;title: Home
;meta(charset "utf-8");
;meta
=name "viewport"
=content "width=device-width, initial-scale=1, shrink-to-fit=no";
;link(rel "stylesheet", href "/~launch/css/index.css");
==
;body
;div#root;
;script@"/~/channel/channel.js";
;script@"/~modulo/session.js";
;* scripts
;script@"/~launch/js/index.js";
==
==

View File

@ -0,0 +1,18 @@
|= scripts=marl
<!doctype html>
<html>
<head>
<title>Home</title>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<link rel="stylesheet" href="/~launch/css/index.css" />
</head>
<body>
<div id="root" />
<script src="/~/channel/channel.js"></script>
<script src="/~modulo/session.js"></script>
<script src="/~launch/js/tiles.js"></script>
<script src="/~launch/js/index.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

114
pkg/arvo/app/lens.hoon Normal file
View File

@ -0,0 +1,114 @@
/- lens
/+ *server
/= lens-mark /: /===/mar/lens/command
/!noun/
=, format
|%
:: +move: output effect
::
+$ move [bone card]
:: +card: output effect payload
::
+$ card
$% [%connect wire binding:eyre term]
[%http-response =http-event:http]
[%peel wire dock mark path]
[%poke wire dock poke]
[%pull wire dock ~]
==
::
+$ poke
$% [%lens-command command:lens]
==
::
+$ state
$% $: %0
job=(unit [=bone com=command:lens])
==
==
::
--
::
|_ [bow=bowl:gall state=state]
::
++ this .
::
++ prep
|= old=(unit *)
^- (quip move _this)
[~ this]
::
:: alerts us that we were bound. we need this because the vane calls back.
::
++ bound
|= [wir=wire success=? binding=binding:eyre]
^- (quip move _this)
[~ this]
::
++ poke-handle-http-request
%- (require-authorization:app ost.bow move this)
|= =inbound-request:eyre
^- (quip move _this)
?^ job.state
:_ this
[ost.bow %http-response %start [%500 ~] ~ %.y]~
::
=/ request-line (parse-request-line url.request.inbound-request)
=/ site (flop site.request-line)
::
=/ jon=json
(need (de-json:html q:(need body.request.inbound-request)))
=/ com=command:lens
(json:grab:lens-mark jon)
:_ this(job.state (some [ost.bow com]))
[ost.bow %peel /sole [our.bow %dojo] %lens-json /sole]~
::
++ diff-lens-json
|= [=wire jon=json]
^- (quip move _this)
?~ jon
[~ this]
?> ?=(^ job.state)
:_ this(job.state ~)
[bone.u.job.state %http-response (json-response:app (json-to-octs jon))]~
::
++ quit
|= =wire
^- (quip move _this)
~& [%quit wire]
[~ this]
::
++ reap
|= [=wire saw=(unit tang)]
^- (quip move _this)
?^ saw
[((slog u.saw) ~) this]
?> ?=(^ job.state)
:_ this
:~ [ost.bow %poke /sole [our.bow %dojo] %lens-command com.u.job.state]
[ost.bow %pull /sole [our.bow %dojo] ~]
==
::
++ coup
|= [=wire saw=(unit tang)]
^- (quip move _this)
?^ saw
[((slog u.saw) ~) this]
[~ this]
::
:: +poke-handle-http-cancel: received when a connection was killed
::
++ poke-handle-http-cancel
|= =inbound-request:eyre
^- (quip move _this)
:: the only long lived connections we keep state about are the stream ones.
::
[~ this]
::
++ poke-noun
|= a=*
^- (quip move _this)
~& poke+a
[~ this]
::
--

51
pkg/arvo/app/modulo.hoon Normal file
View File

@ -0,0 +1,51 @@
/+ *server
|%
:: +move: output effect
::
+$ move [bone card]
:: +card: output effect payload
::
+$ card
$% [%connect wire binding:eyre term]
[%disconnect wire binding:eyre]
[%http-response =http-event:http]
==
::
--
::
|_ [bow=bowl:gall ~]
::
++ this .
::
++ prep
|= old=(unit *)
^- (quip move _this)
?~ old
:_ this
[ost.bow %connect / [~ /'~modulo'] %modulo]~
[~ this]
::
:: alerts us that we were bound. we need this because the vane calls back.
::
++ bound
|= [wir=wire success=? binding=binding:eyre]
^- (quip move _this)
[~ this]
::
++ session-js
^- octs
%- as-octt:mimes:html
;: weld
"window.ship = '{+:(scow %p our.bow)}';"
"window.urb = new Channel();"
==
::
:: +poke-handle-http-request: received on a new connection established
::
++ poke-handle-http-request
%- (require-authorization:app ost.bow move this)
|= =inbound-request:eyre
^- (quip move _this)
[[ost.bow %http-response (js-response:app session-js)]~ this]
::
--

481
pkg/arvo/app/ph.hoon Normal file
View File

@ -0,0 +1,481 @@
:: Test the pH of your aquarium. See if it's safe to put in real fish.
::
:: usage:
:: :aqua [%run-test %test-add]
::
:: TODO:
:: - Restore a fleet
:: - Compose tests
::
/- aquarium, ph
/+ ph, ph-tests, ph-azimuth, ph-philter
=, ph-sur=^ph
=, aquarium
=, ph
=, ph-philter
=> $~ |%
+$ move (pair bone card)
+$ card
$% [%poke wire dock poke-type]
[%peer wire dock path]
[%pull wire dock ~]
[%diff diff-type]
==
::
+$ poke-type
$% [%aqua-events (list aqua-event)]
[%drum-start term term]
[%aqua-vane-control ?(%subscribe %unsubscribe)]
==
::
+$ diff-type
$% [%aqua-effects aqua-effects]
==
::
+$ state
$: %0
test-core=(unit test-core-state)
tests=(map term [(list ship) _*form:(ph ,~)])
other-state
==
::
+$ test-core-state
$: lab=term
hers=(list ship)
test=_*form:(ph ,~)
==
::
+$ other-state
$: test-qeu=(qeu term)
results=(list (pair term ?))
effect-log=(list [who=ship uf=unix-effect])
==
--
=, gall
=/ vane-apps=(list term)
~[%aqua-ames %aqua-behn %aqua-dill %aqua-eyre]
|_ $: hid=bowl
state
==
++ this .
++ manual-tests
^- (list (pair term [(list ship) _*form:(ph ,~)]))
=+ (ph-tests our.hid)
=/ eth-node (spawn:ph-azimuth ~bud)
=/ m (ph ,~)
:~ :+ %boot-bud
~[~bud]
(raw-ship ~bud ~)
::
:+ %add
~[~bud]
;< ~ bind:m (raw-ship ~bud ~)
|= pin=ph-input
?: =(%init -.q.uf.pin)
[& (dojo ~bud "[%test-result (add 2 3)]") %wait ~]
?: (is-dojo-output ~bud who.pin uf.pin "[%test-result 5]")
[& ~ %done ~]
[& ~ %wait ~]
::
:+ %hi
~[~bud ~dev]
;< ~ bind:m (raw-ship ~bud ~)
;< ~ bind:m (raw-ship ~dev ~)
(send-hi ~bud ~dev)
::
:+ %boot-planet
~[~bud ~marbud ~linnup-torsyx]
(planet ~linnup-torsyx)
::
:+ %second-cousin-hi
~[~bud ~marbud ~linnup-torsyx ~dev ~mardev ~mitnep-todsut]
;< ~ bind:m (planet ~linnup-torsyx)
;< ~ bind:m (planet ~mitnep-todsut)
(send-hi ~linnup-torsyx ~mitnep-todsut)
::
:+ %change-file
~[~bud]
;< ~ bind:m (raw-ship ~bud ~)
;< file=@t bind:m (touch-file ~bud %home)
(check-file-touched ~bud %home file)
::
:+ %child-sync
~[~bud ~marbud]
;< ~ bind:m (star ~marbud)
;< file=@t bind:m (touch-file ~bud %base)
(check-file-touched ~marbud %home file)
::
:+ %boot-az
~[~bud]
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
(raw-ship ~bud `(dawn:eth-node ~bud))
(pure:m ~)
::
:+ %breach-hi
~[~bud ~dev]
=. eth-node (spawn:eth-node ~dev)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (raw-ship ~bud `(dawn:eth-node ~bud))
;< ~ bind:m (raw-ship ~dev `(dawn:eth-node ~dev))
(send-hi ~bud ~dev)
;< eth-node=_eth-node bind:m
(breach-and-hear:eth-node our.hid ~dev ~bud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (send-hi-not-responding ~bud ~dev)
;< ~ bind:m (raw-ship ~dev `(dawn:eth-node ~dev))
(wait-for-dojo ~bud "hi ~dev successful")
(pure:m ~)
::
:+ %breach-hi-cousin
~[~bud ~dev ~marbud ~mardev]
=. eth-node (spawn:eth-node ~dev)
=. eth-node (spawn:eth-node ~marbud)
=. eth-node (spawn:eth-node ~mardev)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (raw-ship ~bud `(dawn:eth-node ~bud))
;< ~ bind:m (raw-ship ~dev `(dawn:eth-node ~dev))
;< ~ bind:m (raw-ship ~marbud `(dawn:eth-node ~marbud))
;< ~ bind:m (raw-ship ~mardev `(dawn:eth-node ~mardev))
(send-hi ~marbud ~mardev)
;< eth-node=_eth-node bind:m
(breach-and-hear:eth-node our.hid ~mardev ~marbud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (send-hi-not-responding ~marbud ~mardev)
;< ~ bind:m (raw-ship ~mardev `(dawn:eth-node ~mardev))
(wait-for-dojo ~marbud "hi ~mardev successful")
(pure:m ~)
::
:+ %breach-sync
~[~bud ~marbud]
=. eth-node (spawn:eth-node ~marbud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (raw-ship ~bud `(dawn:eth-node ~bud))
;< ~ bind:m (raw-ship ~marbud `(dawn:eth-node ~marbud))
;< file=@t bind:m (touch-file ~bud %base)
~& %checking-file-touched
(check-file-touched ~marbud %home file)
~& %checked-file-touched
;< eth-node=_eth-node bind:m
(breach-and-hear:eth-node our.hid ~bud ~marbud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (raw-ship ~bud `(dawn:eth-node ~bud))
;< ~ bind:m (just-events (dojo ~bud "|merge %base ~marbud %kids, =gem %this"))
;< file=@t bind:m (touch-file ~bud %base)
;< file=@t bind:m (touch-file ~bud %base)
(check-file-touched ~marbud %home file)
(pure:m ~)
::
:+ %breach-multiple
~[~bud ~marbud]
=. eth-node (spawn:eth-node ~marbud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (raw-ship ~bud `(dawn:eth-node ~bud))
;< ~ bind:m (raw-ship ~marbud `(dawn:eth-node ~marbud))
;< file=@t bind:m (touch-file ~bud %base)
(check-file-touched ~marbud %home file)
;< eth-node=_eth-node bind:m
(breach-and-hear:eth-node our.hid ~bud ~marbud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
(raw-ship ~bud `(dawn:eth-node ~bud))
;< eth-node=_eth-node bind:m
(breach-and-hear:eth-node our.hid ~marbud ~bud)
;< [eth-node=_eth-node ~] bind:m
%+ (wrap-philter ,_eth-node ,~)
router:eth-node
;< ~ bind:m (raw-ship ~marbud `(dawn:eth-node ~marbud))
;< file=@t bind:m (touch-file ~bud %base)
;< file=@t bind:m (touch-file ~bud %base)
(check-file-touched ~marbud %home file)
(pure:m ~)
==
::
++ install-tests
^+ this
=. tests (malt manual-tests)
this
::
++ prep
|= old=(unit [@ tests=* rest=*])
^- (quip move _this)
~& prep=%ph
=. this install-tests
`this
:: ?~ old
:: `this
:: =/ new ((soft other-state) rest.u.old)
:: ?~ new
:: `this
:: `this(+<+>+> u.new)
::
++ publish-aqua-effects
|= afs=aqua-effects
^- (list move)
%+ murn ~(tap by sup.hid)
|= [b=bone her=ship pax=path]
^- (unit move)
?. ?=([%effects ~] pax)
~
`[b %diff %aqua-effects afs]
::
++ run-events
|= [lab=term what=(list ph-event)]
^- (quip move _this)
?: =(~ what)
`this
=/ res
|- ^- (each (list aqua-event) ?)
?~ what
[%& ~]
?: ?=(%test-done -.i.what)
[%| p.i.what]
=/ nex $(what t.what)
?: ?=(%| -.nex)
nex
[%& `aqua-event`i.what p.nex]
?: ?=(%| -.res)
=^ moves-1 this (finish-test lab p.res)
=^ moves-2 this run-test
[(weld moves-1 moves-2) this]
[[ost.hid %poke /running [our.hid %aqua] %aqua-events p.res]~ this]
::
:: Cancel subscriptions to ships
::
++ finish-test
|= [lab=term success=?]
^- (quip move _this)
?~ test-core
`this
~& ?: success
"TEST {(trip lab)} SUCCESSFUL"
"TEST {(trip lab)} FAILED"
:_ this(test-core ~, results [[lab success] results])
%- zing
%+ turn hers.u.test-core
|= her=ship
^- (list move)
:~ [ost.hid %pull /[lab]/(scot %p her) [our.hid %aqua] ~]
:* ost.hid
%poke
/cancelling
[our.hid %aqua]
%aqua-events
[%pause-events her]~
==
==
::
:: Start another test if one is in the queue
::
++ run-test
^- (quip move _this)
?^ test-core
`this
?: =(~ test-qeu)
?~ results
`this
=/ throw-away print-results
`this(results ~)
=^ lab test-qeu ~(get to test-qeu)
~& [running-test=lab test-qeu]
=. effect-log ~
=+ ^- [ships=(list ship) test=_*form:(ph ,~)]
(~(got by tests) lab)
=> .(test-core `(unit test-core-state)`test-core)
=. test-core `[lab ships test]
=^ moves-1 this (subscribe-to-effects lab ships)
=^ moves-2 this
(diff-aqua-effects /[lab]/(scot %p -.ships) -.ships [/ %init ~]~)
[:(weld init-vanes pause-fleet subscribe-vanes moves-1 moves-2) this]
::
:: Print results with ~&
::
++ print-results
~& "TEST REPORT:"
=/ throw-away
%+ turn
results
|= [lab=term success=?]
~& "{?:(success "SUCCESS" "FAILURE")}: {(trip lab)}"
~
~& ?: (levy results |=([term s=?] s))
"ALL TESTS SUCCEEDED"
"FAILURES"
~
::
:: Should check whether we're already subscribed
::
++ subscribe-to-effects
|= [lab=@tas hers=(list ship)]
:_ this
%+ turn hers
|= her=ship
^- move
:* ost.hid
%peer
/[lab]/(scot %p her)
[our.hid %aqua]
/effects/(scot %p her)
==
::
:: Start the vane drivers
::
++ init-vanes
^- (list move)
%+ murn
`(list term)`[%aqua vane-apps]
|= vane-app=term
^- (unit move)
=/ app-started
.^(? %gu /(scot %p our.hid)/[vane-app]/(scot %da now.hid))
?: app-started
~
`[ost.hid %poke /start [our.hid %hood] %drum-start %home vane-app]
::
:: Restart the vane drivers' subscriptions
::
++ subscribe-vanes
^- (list move)
%+ turn
vane-apps
|= vane-app=term
[ost.hid %poke /init [our.hid vane-app] %aqua-vane-control %subscribe]
::
:: Pause all existing ships
::
++ pause-fleet
^- (list move)
:_ ~
:* ost.hid %poke /pause-fleet [our.hid %aqua] %aqua-events
%+ turn
.^((list ship) %gx /(scot %p our.hid)/aqua/(scot %da now.hid)/ships/noun)
|= who=ship
[%pause-events who]
==
::
:: User interface
::
++ poke-ph-command
|= com=cli:ph-sur
^- (quip move _this)
?- -.com
%init [init-vanes this]
%run
?. (~(has by tests) lab.com)
~& [%no-test lab.com]
`this
=. test-qeu (~(put to test-qeu) lab.com)
run-test
::
%cancel
=^ moves-1 this (finish-test %last |)
=. test-qeu ~
=^ moves-2 this run-test
[:(weld moves-1 moves-2) this]
::
%run-all
=. test-qeu
%- ~(gas to test-qeu)
(turn manual-tests head)
run-test
::
%print
~& lent=(lent effect-log)
~& %+ roll effect-log
|= [[who=ship uf=unix-effect] ~]
?: ?=(?(%blit %doze) -.q.uf)
~
?: ?=(%ergo -.q.uf)
~& [who [- +<]:uf %omitted-by-ph]
~
~& [who uf]
~
`this
==
::
:: Receive effects back from aqua
::
++ diff-aqua-effects
|= [way=wire afs=aqua-effects]
^- (quip move _this)
:: ~& [%diff-aqua-effect way who.afs]
?> ?=([@tas @ ~] way)
=/ lab i.way
?~ test-core
~& [%ph-dropping-done lab]
[[ost.hid %pull way [our.hid %aqua] ~]~ this]
?. =(lab lab.u.test-core)
~& [%ph-dropping-strange lab]
[[ost.hid %pull way [our.hid %aqua] ~]~ this]
=+ |- ^- $: thru-effects=(list unix-effect)
events=(list ph-event)
log=_effect-log
done=(unit ?)
test=_test.u.test-core
==
?~ ufs.afs
[~ ~ ~ ~ test.u.test-core]
=/ m-res=_*output:(ph ,~)
(test.u.test-core now.hid who.afs i.ufs.afs)
=? ufs.afs =(%cont -.next.m-res)
[i.ufs.afs [/ %init ~] t.ufs.afs]
=^ done=(unit ?) test.u.test-core
?- -.next.m-res
%wait [~ test.u.test-core]
%cont [~ self.next.m-res]
%fail [`| test.u.test-core]
%done [`& test.u.test-core]
==
=+ ^- _$
?~ done
$(ufs.afs t.ufs.afs)
[~ ~ ~ done test.u.test-core]
:^ ?: thru.m-res
[i.ufs.afs thru-effects]
thru-effects
(weld events.m-res events)
[[who i.ufs]:afs log]
[done test]
=. test.u.test-core test
=. effect-log (weld log effect-log)
=> .(test-core `(unit test-core-state)`test-core)
?^ done
=^ moves-1 this (finish-test lab u.done)
=^ moves-2 this run-test
[(weld moves-1 moves-2) this]
=/ moves-1 (publish-aqua-effects who.afs thru-effects)
=^ moves-2 this (run-events lab events)
[(weld moves-1 moves-2) this]
::
:: Subscribe to effects
::
++ peer-effects
|= pax=path
^- (quip move _this)
?. ?=(~ pax)
~& [%ph-bad-peer-effects pax]
`this
`this
::
:: Subscription cancelled
::
++ pull
|= pax=path
`+>.$
--

1424
pkg/arvo/app/publish.hoon Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,21 @@
|= inject=json
^- manx
;html
::
;head
;title: Publish
;meta(charset "utf-8");
;meta
=name "viewport"
=content "width=device-width, initial-scale=1, shrink-to-fit=no";
;link(rel "stylesheet", href "/~publish/index.css");
;script@"/~/channel/channel.js";
;script@"/~modulo/session.js";
;script: window.injectedState = {(en-json:html inject)}
==
::
;body
;div#root;
;script@"/~publish/index.js";
==
==

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

385
pkg/arvo/app/send-txs.hoon Normal file
View File

@ -0,0 +1,385 @@
::
:: there's a small state machine here that goes like this (happy path):
:: =/ wen ~
:: apex
:: -> [if =(~ wen)]
:: -> apex
:: [else]
:: -> wen=`(add now ~s10)
:: -> send-next-batch
:: [n times]
:: -> eth-send-raw-transaction
:: -> sigh-send
:: -> wait 30s in behn
:: -> wake-see
:: [n times]
:: -> wen=~
:: -> eth-get-transaction-receipt
:: -> sigh-see
:: -> apex
::
|%
++ state
$: txs=(list @ux)
see=(set @ux)
wen=(unit @da)
outstanding-send=_|
==
::
++ move (pair bone card)
++ card
$% [%hiss wire ~ mark %hiss hiss:eyre]
[%info wire ship desk nori:clay]
[%rest wire @da]
[%wait wire @da]
==
--
::
|_ [bol=bowl:gall state]
::
++ this .
++ pretty-see (turn (sort (turn ~(tap in see) mug) lth) @p)
::
++ prep
|= old=(unit *)
?: ?=([~ * * ~ @da] old)
~& [%cancelling +>+>.old]
[[ost.bol %rest /see +>+>.old]~ ..prep]
[~ ..prep]
::
:: usage:
::
:: generate txs starting from nonce 0 on fake chain at 11 gwei
:: from address; store at path
:: :send-txs [%gen %/txs/eth-txs %fake 0 11 '0x0000000']
::
:: sign txs for gasses of 2 and 11 gwei; (~ for default gwei set)
:: store at path
:: :send-txs [%sign %/txs %/txs/eth-txs %/pk/txt ~[2 0]]
::
:: read nonce range from signed transactions at path
:: :send-txs [%read %txs/txt]
::
:: send all but first 50 txs from path
:: :send-txs [%send %/txs/txt 50]
::
++ poke-noun
|= $% [%sign bout=path in=path key=path gasses=(list @ud)]
::
[%read pax=path]
::
$: %send
pax=path
how=?(%nonce %number) :: tx nonce / index in file
range=(unit $@(@ud (pair @ud @ud))) :: inclusive. end optional
==
==
^- [(list move) _this]
?- +<-
%sign
:_ this
%+ turn
?. =(~ gasses) gasses
:: default gwei set
~[3 4 6 9 11 21 31]
|= gas=@ud
%+ write-file-wain
:: add gas amount to path
=+ end=(dec (lent bout))
=- (weld (scag end bout) -)
?: =(0 gas) [(snag end bout) /txt]
:_ /txt
(cat 3 (snag end bout) (crip '-' ((d-co:co 1) gas)))
::
%- sign
:+ in key
:: modify tx gas if non-zero gwei specified
?: =(0 gas) ~
`(mul gas 1.000.000.000)
::
%read
=+ tox=.^((list cord) %cx pax)
=+ [first last]=(read-nonces tox)
~& %+ weld
"Found nonces {(scow %ud first)} through {(scow %ud last)}"
" in {(scow %ud (lent tox))} transactions."
[~ this]
::
%send
~& 'loading txs...'
=. see ~
=/ tox=(list cord) .^((list cord) %cx pax)
=. tox
?~ range tox
=* r u.range
?: ?=(%number how)
?@ r
(slag r tox)
%+ slag p.r
(scag q.r tox)
=+ [first last]=(read-nonces tox)
?: !=((lent tox) +((sub last first)))
~| 'woah, probably non-contiguous set of transactions'
!!
?@ r
(slag (sub r first) tox)
(slag (sub p.r first) (scag (sub +(q.r) first) tox))
=. txs
%+ turn tox
(cork trip tape-to-ux)
~& [(lent txs) 'loaded txs']
~& [%clearing-see ~(wyt in see)]
=. see ~
=. outstanding-send |
apex
==
::
++ get-file
|= pax=path
~| pax
.^ (list cord) %cx
(weld /(scot %p our.bol)/home/(scot %da now.bol) pax)
==
::
:: sign pre-generated transactions
++ sign
=, rpc:ethereum
|= [in=path key=path gas=(unit @ud)]
^- (list cord)
?> ?=([@ @ @ *] key)
=/ pkf (get-file t.t.t.key)
?> ?=(^ pkf)
=/ pk (rash i.pkf ;~(pfix (jest '0x') hex))
=/ txs .^((list transaction) %cx in)
=/ enumerated
=/ n 1
|- ^- (list [@ud transaction])
?~ txs
~
[[n i.txs] $(n +(n), txs t.txs)]
%+ turn enumerated
|= [n=@ud tx=transaction]
~? =(0 (mod n 100)) [%signing n]
=? gas-price.tx ?=(^ gas) u.gas
(crip '0' 'x' ((x-co:co 0) (sign-transaction:key:ethereum tx pk)))
::
++ read-nonces
|= tox=(list cord)
^- [@ud @ud]
?: =(~ tox) :: not ?~ because fucking tmi
[0 0]
:- (read-nonce (snag 0 tox))
(read-nonce (snag (dec (lent tox)) tox))
::
++ read-nonce
|= tex=cord
^- @ud
::NOTE this is profoundly stupid but should work well enough
=+ (find "82" (trip tex))
?> ?=(^ -)
(rash (rsh 3 (add u 2) (end 3 (add u 6) tex)) hex)
::
++ write-file-wain
|= [pax=path tox=(list cord)]
^- move
?> ?=([@ desk @ *] pax)
:* ost.bol
%info
(weld /write pax)
our.bol
i.t.pax
=- &+[t.t.t.pax -]~
=/ y .^(arch %cy pax)
?~ fil.y
ins+txt+!>(tox)
mut+txt+!>(tox)
==
::
++ write-file-transactions
|= [pax=path tox=(list transaction:rpc:ethereum)]
^- move
?> ?=([@ desk @ *] pax)
:* ost.bol
%info
(weld /write pax)
our.bol
i.t.pax
=- &+[t.t.t.pax -]~
=/ y .^(arch %cy pax)
?~ fil.y
ins+eth-txs+!>(tox)
mut+eth-txs+!>(tox)
==
::
++ fan-requests
|= [wir=wire nodes=(list [tag=@tas url=purl:eyre]) jon=json]
:: =- ~& [batch=((list ,[bone * wire]) (turn - |=(* [- +< +>-]:+<))) jon=jon] -
^- (list move)
%+ turn nodes
|= [tag=@tas url=purl:eyre]
^- move
:- ost.bol
:^ %hiss (weld wir ~[tag]) ~
:+ %json-rpc-response %hiss
(json-request:rpc:ethereum url jon)
::
++ batch-requests
|= [wir=wire req=(list [(unit @t) request:rpc:ethereum])]
^- (list move)
%^ fan-requests
wir
:~ => (need (de-purl:html 'http://35.226.110.143:8545'))
geth+.(p.p |)
::
=> (need (de-purl:html 'http://104.198.35.227:8545'))
parity+.(p.p |)
==
a+(turn req request-to-json:rpc:ethereum)
::
++ send-next-batch
^- [(list move) _this]
?: outstanding-send
~& 'waiting for previous send to complete'
`this
?: =(0 (lent txs))
~& 'all sent!'
[~ this(txs ~, see ~, wen ~, outstanding-send |)]
:: ~& send-next-batch=pretty-see
=/ new-count (sub 500 ~(wyt in see))
?: =(0 new-count)
~& %no-new-txs-yet
`this
:_ this(txs (slag new-count txs), outstanding-send &)
~& ['remaining txs: ' (lent txs)]
~& ['sending txs...' new-count]
%+ batch-requests /send
%+ turn (scag new-count txs)
|= tx=@ux
:- `(crip 'id-' (scot %ux (end 3 10 tx)) ~)
[%eth-send-raw-transaction tx]
::
++ sigh-json-rpc-response-send
|= [wir=wire res=response:rpc:jstd]
^- [(list move) _this]
?: ?=(%fail -.res)
~& %send-failed
`this
?> ?=(%batch -.res)
:: ~& sigh-send-a=pretty-see
=. see
%- ~(uni in see)
%- silt
^- (list @ux)
%+ murn bas.res
|= r=response:rpc:jstd
^- (unit @ux)
?: ?=(%error -.r)
?: ?| =('known transaction' (end 3 17 message.r))
=('Known transaction' (end 3 17 message.r))
=('Transaction with the same ' (end 3 26 message.r))
==
~& [%sent-a-known-transaction--skipping wir]
~
?: =('Nonce too low' message.r)
~& %nonce-too-low--skipping
~
~| :- 'transaction send failed, game over'
[code.r message.r]
!!
?> ?=(%result -.r)
:- ~
%- tape-to-ux
(sa:dejs:format res.r)
=. outstanding-send |
:: ~& sigh-send-b=pretty-see
`this
::
++ apex
^- [(list move) _this]
~& :_ ~(wyt in see)
'waiting for transaction confirms... '
?. =(~ wen) [~ this]
=. wen `(add now.bol ~s30)
:: ~& apex=[wen pretty-see]
=^ moves this send-next-batch
:: timer got un-set, meaning we're done here
?~ wen [moves this]
[[[ost.bol %wait /see (need wen)] moves] this]
::
++ wake-see
|= [wir=wire ~]
^- [(list move) _this]
=. wen ~
:: ~& wake-see=[wen pretty-see]
?: =(~ see)
apex
:_ this
%+ batch-requests /see
%+ turn ~(tap in see)
|= txh=@ux
:- `(crip 'see-0x' ((x-co:co 64) txh))
[%eth-get-transaction-receipt txh]
::
++ sigh-json-rpc-response-see
|= [wir=wire res=response:rpc:jstd]
^- [(list move) _this]
?: ?| ?=(%error -.res)
?=(%fail -.res)
==
~& [%bad-rpc-response--kicking res]
apex
:: `this
?> ?=(%batch -.res)
?: =(~ see)
apex
?: =(0 (lent bas.res))
::TODO node lost our txs?
~& [%txs-lost-tmp wir '!!']
apex
:: ~& sigh-see-a=pretty-see
=. see
%- ~(dif in see)
%- silt
^- (list @ux)
%+ murn bas.res
|= r=response:rpc:jstd
^- (unit @ux)
?< ?=(%batch -.r)
?< ?=(%fail -.r)
~| [id.r res]
=+ txh=(tape-to-ux (trip (rsh 3 4 id.r)))
:: ~& see-tx=[(@p (mug txh)) `@ux`txh]
=* done `txh
=* wait ~
?: ?=(%error -.r)
~& :- 'receipt fetch error'
[code.r message.r]
wait
?~ res.r wait
?> ?=(%o -.res.r)
=/ status
%- tape-to-ux
%- sa:dejs:format
(~(got by p.res.r) 'status')
?: =(1 status)
done
~& [%see-bad-status status]
wait
:: ~& sigh-see-b=pretty-see
apex
::
++ sigh-tang
|= [wir=wire err=tang]
~& [%sigh-tang wir]
~& (slog err)
?: =(~ wen) [~ this]
=. wen `(add now.bol ~s30)
[[ost.bol %wait /see (need wen)]~ this]
::
++ tape-to-ux
|= t=tape
(scan t zero-ux)
::
++ zero-ux
;~(pfix (jest '0x') hex)
--

2566
pkg/arvo/app/talk.hoon Normal file

File diff suppressed because it is too large Load Diff

170
pkg/arvo/app/test.hoon Normal file
View File

@ -0,0 +1,170 @@
::
|%
++ test
$% [%arvo ~] ::UNIMPLEMENTED
[%marks ~] ::UNIMPLEMENTED
[%cores p=path]
[%hoons p=path]
[%names p=path]
[%renders p=path]
==
--
::
|%
++ join
|= {a/cord b/(list cord)}
?~ b ''
(rap 3 |-([i.b ?~(t.b ~ [a $(b t.b)])]))
::
++ fake-fcgi [%many [%blob *cred:eyre] $+[%n ~] ~]
--
::
=, gall
=, ford
=, format
|_ {bowl $~}
::
++ peek _~
::
++ report-error
|= [=spur bud=build-result]
^- tang
=/ should-fail (~(get by failing) (flop spur))
?- -.bud
%success
?~ should-fail ~
:~ leaf+"warn: expected failure, {<`tape`u.should-fail>}"
leaf+"warn: built succesfully"
?: ?=(%bake +<.bud)
(sell q.cage.bud)
?> ?=(%core +<.bud)
(sell vase.bud)
==
::
%error
?^ should-fail
~[>[%failed-known `tape`(weld "TODO: " u.should-fail)]<]
(flop message.bud)
==
::
++ made-a-core
|= [=spur @da res=made-result]
:_ +>.$
?: ?=([%incomplete *] res)
~& incomplete-core+spur
((slog tang.res) ~)
?. ?=([%complete %success *] res)
~& unsuccessful-core+spur
((slog message.build-result.res) ~)
?> ?=(^ +<.build-result.res)
%- (slog (report-error spur head.build-result.res))
=/ nex=(list ^spur)
=< p
;; [%success %$ %cont * p=(list ^spur)]
tail.build-result.res
?~ nex ~&(%cores-tested ~)
[ost (build-core nex)]~
::
++ build-core
|= [a=spur b=(list spur)]
~& >> (flop a)
:- %build
:+ a-core+a
live=|
^- schematic:ford
:- [%core now-disc %hoon a]
[%$ %cont !>(b)]
::
++ made-a-rend
|= [=spur @da res=made-result]
:_ +>.$
?> ?=([ren=term ~] spur)
=+ `[ren=term pax=path]`?~(spur !! spur)
?: ?=([%incomplete *] res)
~& incomplete-core+spur
((slog tang.res) ~)
?. ?=([%complete %success *] res)
~& unsuccessful-core+spur
((slog message.build-result.res) ~)
?> ?=(^ +<.build-result.res)
%- (slog (report-error /[ren]/ren head.build-result.res))
=/ nex=(list term)
=< p
;; [%success %$ %cont * p=(list term)]
tail.build-result.res
?~ nex ~&(%rens-tested ~)
[ost (build-rend nex)]~
::
++ build-rend
|= [a=term b=(list term)]
~& >> [%ren a]
:- %build
:+ a-rend+/[a]
live=|
^- schematic:ford
=/ bem=beam (need (de-beam %/example))
=/ =rail [[p q] s]:bem
:- [%bake a fake-fcgi rail]
[%$ %cont !>(b)]
::
++ poke-noun
|= a=test
:_ +>
?- -.a
%arvo ~|(%stub !!) ::basically double solid?
%hoons ~&((list-hoons p.a ~) ~)
%cores [ost (build-core [- +]:(list-hoons p.a skip=(sy /sys /ren /tests ~)))]~
%names ~&((list-names p.a) ~)
%marks ~|(%stub !!) ::TODO restore historical handler
%renders ~&(%all-renderers-are-disabled ~)
==
::
++ list-names
|= a/path ^- (list term)
=/ hon (list-hoons a ~)
%+ turn hon
|= b=spur
(join '-' (slag 1 (flop b)))
::
++ list-hoons
|= [under=path skipping=(set spur)] ^- (list spur)
=/ sup (flop under)
~& [%findining-hoons under=under]
|- ^- (list spur)
%- zing
%+ turn
=- (sort ~(tap by -) aor)
dir:.^(arch %cy (en-beam now-beak sup))
|= [a=knot ~] ^- (list spur)
=. sup [a sup]
?: (~(has in skipping) (flop sup))
~&(> [(flop sup) %out-of-scope] ~)
=/ ded (~(get by skip-completely) (flop sup))
?^ ded
~&(> [(flop sup) %skipped `tape`u.ded] ~)
?~ [fil:.^(arch %cy (en-beam now-beak [%hoon sup]))]
^$
~& (flop sup)
[sup ^$]
::
++ now-beak %_(byk r [%da now])
++ now-disc `disc:ford`[p.byk q.byk]
++ skip-completely
^~ ^- (map path tape)
%- my :~ ::TODO don't hardcode
:- /ren/run "not meant to be called except on a (different) hoon file"
:- /ren/test-gen "temporarily disabled"
==
::
++ failing
^~ ^- (map path tape)
%- my :~ ::TODO don't hardcode
::
:- /gen/al "compiler types out-of-date"
:- /gen/musk "compiler types out-of-date"
::
:- /gen/cosmetic "incomplete"
:- /gen/lust "incomplete"
:- /gen/scantastic "incomplete"
==
--

View File

@ -0,0 +1,8 @@
:- ~[comments+&]
;>
# Static
You can put static files in here to serve them to the web. Actually, you can put static files anywhere in `/web` and see them in a browser.
Docs on static publishing with urbit are forthcoming — but feel free to drop markdown files in `/web` to try it out.

269
pkg/arvo/app/tiebout.hoon Normal file
View File

@ -0,0 +1,269 @@
/- hall, tiebout
=, tiebout
=, eyre
|%
+$ move [bone card]
::
+$ card
$% [%poke wire dock poke]
[%peer wire dock path]
[%pull wire dock ~]
[%diff diff]
[%hiss wire [~ ~] %httr %hiss hiss]
==
::
+$ diff
$% [%hall-rumor rumor:hall]
[%tiebout-action action]
==
::
+$ poke
$% [%tiebout-action action]
==
::
+$ state
$% [%0 tiebout-zero]
==
::
+$ tiebout-zero
$:
:: iOS device token
::
token=@t
:: ship that routes notifications to Apple
::
king=@p
:: url of Apple server to send notifications to
::
baseurl=@t
:: name and last read
::
circles=(map name:hall @)
==
::
--
::
:: state:
::
|_ [bol=bowl:gall sta=state]
::
:: +this: app core subject
::
++ this .
::
:: +prep: set up app state, upgrade app state
::
++ prep
|= old=(unit state)
^- (quip move _this)
?~ old
:- ~
%= this
king.sta ~dabben-larbet
baseurl.sta 'https://api.push.apple.com/3/device/'
==
?- -.u.old
%0
[~ this(sta u.old)]
==
::
:: +coup: receive acknowledgement for poke, print error if it failed
::
++ coup
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
[~ this]
(mean u.err)
::
:: +poke-noun: receive debugging actions
::
++ poke-noun
|= act=action
^- (quip move _this)
(poke-tiebout-action act)
::
:: +poke-tiebout-action: main action handler
::
++ poke-tiebout-action
|= act=action
^- (quip move _this)
?- -.act
$king (set-king +.act)
$token (set-token +.act)
$baseurl (set-baseurl +.act)
$add-circle (add-circle +.act)
$del-circle (del-circle +.act)
$notify (send-notify +.act)
==
::
:: +add-circle: add circle and subscribe for updates
::
++ add-circle
|= nom=name:hall
^- (quip move _this)
:_ this(circles.sta (~(put by circles.sta) nom 0))
[ost.bol %peer /our/[nom] [our.bol %hall] /circle/[nom]/config/grams]~
::
:: +del-circle: delete circle and unsubscribe from updates
::
++ del-circle
|= nom=name:hall
^- (quip move _this)
:_ this(circles.sta (~(del by circles.sta) nom))
[ost.bol %pull /our/[nom] [our.bol %hall] ~]~
::
:: +set-king: set king @p
::
++ set-king
|= kng=@p
^- (quip move _this)
[~ this(king.sta kng)]
::
:: +set-token: set iOS device token @t
::
++ set-token
|= tok=@t
^- (quip move _this)
[~ this(token.sta tok)]
::
:: +set-baseurl: set base url @t
::
++ set-baseurl
|= burl=@t
^- (quip move _this)
[~ this(baseurl.sta burl)]
::
:: +send-notify: if king, send hiss. if not, do nothing.
::
++ send-notify
|= not=notification
^- (quip move _this)
?: =(king.sta our.bol)
:_ this
[ost.bol %hiss /request [~ ~] %httr %hiss (create-apns-request not)]~
[~ this]
::
:: +diff-hall-prize: receive new circle data
::
++ diff-hall-prize
|= [wir=wire piz=prize:hall]
^- (quip move _this)
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
:: %our: set config of circle and iterate through messages, sending
:: notifications for all messages where number is higher than our last-read
::
{%our @ @}
?> ?=(%circle -.piz)
=/ nom/name:hall i.t.wir
=/ red/@ud red.loc.cos.piz
[~ this(circles.sta (~(put by circles.sta) nom red))]
==
::
:: +reap: recieve acknowledgement for peer
::
++ reap
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
[~ this]
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
{%our @ @}
?< ?=(~ t.wir)
[~ this]
==
::
:: +quit: receive subscription failed, resubscribe
::
++ quit
|= wir=wire
^- (quip move _this)
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
{%our @ @}
?< ?=(~ t.wir)
:_ this
=/ doc/dock [our.bol %hall]
[ost.bol %peer /our/[i.t.wir] doc /circle/[i.t.wir]/config/grams]~
==
::
:: +diff-hall-rumor: receive message or a read event from a hall circle
::
++ diff-hall-rumor
|= [wir=wire rum=rumor:hall]
^- (quip move _this)
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
:: %our
::
{%our @ @}
?> ?=(%circle -.rum)
=/ nom/name:hall i.t.wir
?+ -.rum.rum
[~ this]
::
:: %gram: send notification if envelope is lower than read number
::
%gram
=/ red (~(get by circles.sta) nom)
?~ red
(mean [leaf+"invalid circle for diff: {(spud wir)}"]~)
?: (gth num.nev.rum.rum u.red)
:_ this(circles.sta (~(put by circles.sta) nom u.red))
(conditional-msg-to-not u.red nev.rum.rum)
:_ this
(conditional-msg-to-not u.red nev.rum.rum)
::
:: %config: set our read number
::
%config
?+ -.dif.rum.rum
[~ this]
::
%read
[~ this(circles.sta (~(put by circles.sta) nom red.dif.rum.rum))]
==
==
==
::
:: generate notification move from hall message if conditions are met
::
++ conditional-msg-to-not
|= [red=@ud env=envelope:hall]
^- (list move)
?: =(aut.gam.env our.bol)
~
=/ pay %- my :~
alert+s+'New message from {(cite:title aut.gam.env)}'
==
=/ not/notification [token.sta 'com.tlon.urbit-client' pay]
?: (lte num.env red)
~
=/ doc/dock [king.sta dap.bol]
[ost.bol %poke /ask-king doc %tiebout-action [%notify not]]~
::
:: +create-apns-request: create hiss with payload for APNs
::
++ create-apns-request
|= not=notification
^- hiss
=/ furl=@t (crip (weld (trip baseurl.sta) (trip token.not)))
=/ url=purl (need (de-purl:html furl))
=/ jon=json :- %o
%- my :~
aps+o+payload.not
==
:^ url %post
%- my :~
apns-topic+[topic.not ~] :: generate map from raw noun
==
(some (as-octt:mimes:html (en-json:html jon)))
--

23
pkg/arvo/app/time.hoon Normal file
View File

@ -0,0 +1,23 @@
::
:::: /hoon/time/app
::
/? 310
|%
++ card {$wait wire @da}
--
|_ {bowl:gall ~}
++ poke-noun
|= *
:_ +>.$ :_ ~
[ost %wait /(scot %da now) +(now)]
::
++ wake
|= {wir/wire error=(unit tang)}
?> ?=({@ ~} wir)
?^ error
%- (slog u.error)
~& %time-behn-failed
[~ +>.$]
~& [%took `@dr`(sub now (slav %da i.wir))]
[~ +>.$]
--

125
pkg/arvo/app/timer.hoon Normal file
View File

@ -0,0 +1,125 @@
/+ *server
/= tile-js
/^ octs
/; as-octs:mimes:html
/: /===/app/timer/js/tile
/| /js/
/~ ~
==
/= timer-png
/^ (map knot @)
/: /===/app/timer/img /_ /png/
=, format
::
|%
:: +move: output effect
::
+$ move [bone card]
:: +card: output effect payload
::
+$ poke
$% [%launch-action [@tas path @t]]
==
::
+$ card
$% [%poke wire dock poke]
[%http-response =http-event:http]
[%connect wire binding:eyre term]
[%diff %json json]
[%wait wire @da]
[%rest wire @da]
==
::
--
::
|_ [bol=bowl:gall tim=@da]
::
++ this .
::
++ bound
|= [wir=wire success=? binding=binding:eyre]
^- (quip move _this)
[~ this]
::
++ prep
|= old=(unit tim=@da)
^- (quip move _this)
=/ launcha [%launch-action [%timer /tile '/~timer/js/tile.js']]
:-
:~
[ost.bol %connect / [~ /'~timer'] %timer]
[ost.bol %poke /timer [our.bol %launch] launcha]
==
?~ old
this
%= this
tim tim.u.old
==
::
++ peer-tile
|= pax=path
^- (quip move _this)
?: =(tim *@da)
[[ost.bol %diff %json [%s '']]~ this]
[[ost.bol %diff %json [%s (scot %da tim)]]~ this]
::
++ send-tile-diff
|= jon=json
^- (list move)
%+ turn (prey:pubsub:userlib /tile bol)
|= [=bone ^]
[bone %diff %json jon]
::
++ poke-json
|= jon=json
^- (quip move _this)
?. ?=(%s -.jon)
[~ this]
=/ str/@t +.jon
?: =(str 'start')
=/ data/@da (add now.bol ~m20)
:_ this(tim data)
[[ost.bol %wait /timer data] (send-tile-diff [%s (scot %da data)])]
?: =(str 'stop')
:_ this(tim *@da)
[[ost.bol %rest /timer tim] (send-tile-diff [%s ''])]
[~ this]
::
++ 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)
=/ back-path (flop site.request-line)
=/ name=@t
=/ back-path (flop site.request-line)
?~ back-path
''
i.back-path
::
?+ site.request-line
[[ost.bol %http-response not-found:app]~ this]
::
:: tile
::
[%'~timer' %js %tile ~]
[[ost.bol %http-response (js-response:app tile-js)]~ this]
::
:: images
::
[%'~timer' %img *]
=/ img (as-octs:mimes:html (~(got by timer-png) `@ta`name))
:_ this
[ost.bol %http-response (png-response:app img)]~
==
::
++ wake
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
:- (send-tile-diff [%s 'alarm'])
this(tim *@da)
~& err
[~ this]
::
--

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

170
pkg/arvo/app/weather.hoon Normal file
View File

@ -0,0 +1,170 @@
/+ *server
/= tile-js
/^ octs
/; as-octs:mimes:html
/: /===/app/weather/js/tile
/| /js/
/~ ~
==
/= weather-png
/^ (map knot @)
/: /===/app/weather/img /_ /png/
=, format
::
|%
:: +move: output effect
::
+$ move [bone card]
:: +card: output effect payload
::
+$ card
$% [%poke wire dock poke]
[%http-response =http-event:http]
[%diff %json json]
[%connect wire binding:eyre term]
[%request wire request:http outbound-config:iris]
[%wait wire @da]
==
+$ poke
$% [%launch-action [@tas path @t]]
==
+$ state
$% [%0 data=json time=@da location=@t timer=(unit @da)]
==
--
::
|_ [bol=bowl:gall state]
::
++ this .
::
++ bound
|= [wir=wire success=? binding=binding:eyre]
^- (quip move _this)
[~ this]
::
++ prep
|= old=(unit state)
^- (quip move _this)
=/ launcha
[%launch-action [%weather /weathertile '/~weather/js/tile.js']]
:-
:~
[ost.bol %connect / [~ /'~weather'] %weather]
[ost.bol %poke /weather [our.bol %launch] launcha]
==
?~ old
this
%= this
data data.u.old
time time.u.old
==
::
++ peer-weathertile
|= pax=path
^- (quip move _this)
[[ost.bol %diff %json data]~ this]
::
++ poke-json
|= jon=json
^- (quip move _this)
?. ?=(%s -.jon)
[~ this]
=/ str/@t +.jon
=/ req/request:http (request-darksky str)
=/ out *outbound-config:iris
=/ lismov [ost.bol %request /[(scot %da now.bol)] req out]~
?~ timer
:- [[ost.bol %wait /timer (add now.bol ~h3)] lismov]
%= this
location str
timer `(add now.bol ~h3)
==
:- lismov
%= this
location str
==
::
++ request-darksky
|= location=@t
^- request:http
=/ url/@t
%- crip %+ weld
(trip 'https://api.darksky.net/forecast/634639c10670c7376dc66b6692fe57ca/')
(trip location)
=/ hed [['Accept' 'application/json']]~
[%'GET' url hed *(unit octs)]
::
++ send-tile-diff
|= jon=json
^- (list move)
%+ turn (prey:pubsub:userlib /weathertile bol)
|= [=bone ^]
[bone %diff %json jon]
::
++ http-response
|= [=wire response=client-response:iris]
^- (quip move _this)
:: ignore all but %finished
?. ?=(%finished -.response)
[~ this]
=/ data/(unit mime-data:iris) full-file.response
?~ data
:: data is null
[~ this]
=/ ujon/(unit json) (de-json:html q.data.u.data)
?~ ujon
[~ this]
?> ?=(%o -.u.ujon)
?: (gth 200 status-code.response-header.response)
~& weather+u.ujon
~& weather+location
[~ this]
=/ jon/json %- pairs:enjs:format :~
currently+(~(got by p.u.ujon) 'currently')
daily+(~(got by p.u.ujon) 'daily')
==
:- (send-tile-diff jon)
%= this
data jon
time now.bol
==
::
++ 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)
=/ back-path (flop site.request-line)
=/ name=@t
=/ back-path (flop site.request-line)
?~ back-path
''
i.back-path
::
?~ back-path
:_ this ~
?: =(name 'tile')
[[ost.bol %http-response (js-response:app tile-js)]~ this]
?: (lte (lent back-path) 1)
[[ost.bol %http-response not-found:app]~ this]
?: =(&2:site.request-line 'img')
=/ img (as-octs:mimes:html (~(got by weather-png) `@ta`name))
[[ost.bol %http-response (png-response:app img)]~ this]
[~ this]
::
++ wake
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
=/ req/request:http (request-darksky location)
=/ out *outbound-config:iris
=/ lismov/(list move)
[ost.bol %request /[(scot %da now.bol)] req out]~
?~ timer
:- [[ost.bol %wait /timer (add now.bol ~h3)] lismov]
this(timer `(add now.bol ~h3))
[lismov this]
~& err
[~ this]
::
--

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

Some files were not shown because too many files have changed in this diff Show More