Merge branch 'master' into m/next-gen-term

This commit is contained in:
Fang 2021-08-12 14:43:24 +02:00
commit da85ee2e38
No known key found for this signature in database
GPG Key ID: EB035760C1BBA972
200 changed files with 29704 additions and 11691 deletions

3
.eslintrc.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
ignorePatterns: ["**/*"]
};

View File

@ -1,4 +1,4 @@
FROM jaredtobin/janeway:v0.15.3.1
FROM tloncorp/janeway:v0.15.4
COPY entrypoint.sh /entrypoint.sh
EXPOSE 22/tcp
ENTRYPOINT ["/entrypoint.sh"]

View File

@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- run: cd 'pkg/interface' && npm i
- run: npm i && npm run bootstrap
- name: Publish to Chromatic
uses: chromaui/action@v1
with:

24
.github/workflows/frontend-test.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: frontend-test
on:
pull_request:
paths:
- 'pkg/interface/**'
- 'pkg/btc-wallet/**'
- 'pkg/npm/**'
jobs:
frontend-test:
runs-on: ubuntu-latest
name: "Test changed frontend packages"
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- run: git fetch --prune
- name: 'Setup root deps'
run: npm ci
- name: 'Setup dependencies'
run: npm run bootstrap
- name: 'Run tests'
run: npm run test -- --since origin/$GITHUB_BASE_REF --include-dependents

View File

@ -1,14 +0,0 @@
name: typescript-check
on:
pull_request:
paths:
- 'pkg/interface/**'
jobs:
typescript-check:
runs-on: ubuntu-latest
name: "Check pkg/interface types"
steps:
- uses: actions/checkout@v2
- run: cd 'pkg/interface' && npm i && npm run tsc

1
.gitignore vendored
View File

@ -33,6 +33,7 @@ result-*
# NodeJS
node_modules
.eslintcache
# Haskell
.stack-work

1
.husky/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
_

View File

@ -1,10 +1,8 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd pkg/interface
command -v npx > /dev/null || {
exit 0
}
npx lint-staged
npx lint-staged

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5f62579d654a145904ffb0bc9bbda17dda091a2e28e2f1eecf6a7b29cef9189c
size 14866258
oid sha256:2d96d97b5adb6896057d21557803a046eb6a7c024629ed03209f245df5c67d42
size 13205353

8
lerna.json Normal file
View File

@ -0,0 +1,8 @@
{
"packages": [
"pkg/npm/*",
"pkg/btc-wallet",
"pkg/interface"
],
"version": "independent"
}

6915
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "root",
"private": true,
"devDependencies": {
"eslint": "^7.29.0",
"husky": "^6.0.0",
"lerna": "^4.0.0",
"lint-staged": "^11.0.0"
},
"scripts": {
"watch-libs": "lerna run watch --no-private --parallel",
"build-libs": "lerna run build --no-private",
"test": "lerna run test",
"prepare": "husky install .husky",
"bootstrap": "lerna bootstrap",
"build:prod": "lerna run build:prod"
},
"lint-staged": {
"*.{js,ts,tsx}": "eslint --cache --fix"
}
}

View File

@ -11,21 +11,25 @@
::
/- *bitcoin, json-rpc, *btc-provider
/+ dbug, default-agent, bl=btc, groupl=group, resource
~% %btc-provider-top ..part ~
|%
+$ card card:agent:gall
+$ versioned-state
$% state-0
state-1
state-2
==
::
+$ state-0 [%0 =host-info =whitelist]
::
+$ card card:agent:gall
::
+$ state-1 [%1 =host-info =whitelist timer=(unit @da)]
+$ state-2 [%2 =host-info =whitelist timer=(unit @da) interval=@dr]
--
%- agent:dbug
=| state-0
=| state-2
=* state -
^- agent:gall
=<
~% %btc-provider-agent ..send-status ~
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
@ -33,13 +37,13 @@
::
++ on-init
^- (quip card _this)
~& > '%btc-provider initialized successfully'
=| wl=^whitelist
:- ~
%_ this
host-info
['' connected=%.n %main block=0 clients=*(set ship)]
whitelist wl(public %.n, kids %.n)
host-info ['' connected=%.n %main block=0 clients=*(set ship)]
whitelist wl(public %.n, kids %.n)
timer ~
interval ~m1
==
::
++ on-save
@ -49,24 +53,144 @@
++ on-load
|= old-state=vase
^- (quip card _this)
~& > '%btc-provider recompiled successfully '
`this(state !<(versioned-state old-state))
=/ old !<(versioned-state old-state)
?- -.old
%2
[~ this(state old)]
::
%1
`this(state [%2 host-info.old whitelist.old timer.old ~m1])
::
%0
:_ this(state [%2 host-info.old whitelist.old ~ ~m1])
?: =('' api-url.host-info.old) ~
~[(start-ping-timer:hc ~s0)]
==
::
++ on-poke
~/ %on-poke
|= [=mark =vase]
^- (quip card _this)
|^
?> ?|((team:title our.bowl src.bowl) (is-client:hc src.bowl))
=^ cards state
?+ mark (on-poke:def mark vase)
%btc-provider-command
?> (team:title our.bowl src.bowl)
(handle-command:hc !<(command vase))
(handle-command !<(command vase))
::
%btc-provider-action
(handle-action:hc !<(action vase))
(handle-action !<(action vase))
::
%noun
?. =(q.vase %kick-timer) `state
:_ state(timer `now.bowl)
:* (start-ping-timer ~s0)
?~ timer ~
[[%pass /block-time %arvo %b %rest u.timer] ~]
==
==
[cards this]
::
++ handle-command
|= comm=command
^- (quip card _state)
?- -.comm
%set-credentials
:_ %_ state
host-info [api-url.comm %.n network.comm 0 *(set ship)]
timer `now.bowl
==
:* (start-ping-timer:hc ~s0)
?~ timer ~
[[%pass /block-time %arvo %b %rest u.timer] ~]
==
::
%add-whitelist
:- ~
?- -.wt.comm
%public
state(public.whitelist %.y)
::
%kids
state(kids.whitelist %.y)
::
%users
state(users.whitelist (~(uni in users.whitelist) users.wt.comm))
::
%groups
state(groups.whitelist (~(uni in groups.whitelist) groups.wt.comm))
==
::
%remove-whitelist
=. state
?- -.wt.comm
%public
state(public.whitelist %.n)
::
%kids
state(kids.whitelist %.n)
::
%users
state(users.whitelist (~(dif in users.whitelist) users.wt.comm))
::
%groups
state(groups.whitelist (~(dif in groups.whitelist) groups.wt.comm))
==
clean-client-list
::
%set-interval
`state(interval inte.comm)
==
::
:: +clean-client-list: remove clients who are no longer whitelisted
:: called after a whitelist change
::
++ clean-client-list
^- (quip card _state)
=/ to-kick=(set ship)
%- silt
%+ murn ~(tap in clients.host-info)
|= c=ship ^- (unit ship)
?:((is-whitelisted:hc c) ~ `c)
:_ state(clients.host-info (~(dif in clients.host-info) to-kick))
%+ turn ~(tap in to-kick)
|=(c=ship [%give %kick ~[/clients] `c])
::
:: if not connected, only %ping action is allowed
::
++ handle-action
|= act=action
^- (quip card _state)
:_ state
?. ?|(connected.host-info ?=(%ping -.act))
~[(send-update:hc [%| %not-connected 500] ~)]
:_ ~
%+ req-card act
^- action:rpc-types
?- -.act
%address-info [%get-address-info address.act]
%tx-info [%get-tx-vals txid.act]
%raw-tx [%get-raw-tx txid.act]
%broadcast-tx [%broadcast-tx rawtx.act]
%ping [%get-block-info ~]
%block-info [%get-block-info block.act]
==
::
++ req-card
|= [act=action ract=action:rpc-types]
=/ req=request:http
(gen-request:bl host-info ract)
[%pass (rpc-wire act) %arvo %i %request req *outbound-config:iris]
::
++ rpc-wire
|= act=action
^- wire
/[-.act]/(scot %p src.bowl)/(scot %ux (cut 3 [0 20] eny.bowl))
--
::
++ on-watch
~/ %on-watch
|= pax=path
^- (quip card _this)
:: checking provider permissions before trying to subscribe
@ -83,31 +207,124 @@
==
[%give %fact ~ %json !>(jon)]~
::
?> ?=([%clients *] pax)
?> ?| ?=([%clients ~] pax)
?& ?=([%clients @ ~] pax)
=(src.bowl (slav %p i.t.pax))
==
==
?. (is-whitelisted:hc src.bowl)
~|("btc-provider: blocked client {<src.bowl>}" !!)
~& > "btc-provider: accepted client {<src.bowl>}"
:- [do-ping:hc]~
this(clients.host-info (~(put in clients.host-info) src.bowl))
`this(clients.host-info (~(put in clients.host-info) src.bowl))
::
++ on-arvo
|= [=wire =sign-arvo]
~/ %on-arvo
|= [wir=wire =sign-arvo]
|^
^- (quip card _this)
:: check for connectivity every 30 seconds
::
?: ?=([%ping-timer *] wire)
:_ this
:~ do-ping:hc
(start-ping-timer:hc ~s30)
?: ?=([%ping-timer *] wir)
`this
?: ?=([%block-ping *] wir)
:_ this(timer `(add now.bowl interval))
:~ do-ping
(start-ping-timer:hc interval)
==
=^ cards state
?+ +<.sign-arvo (on-arvo:def wire sign-arvo)
%http-response
(handle-rpc-response:hc wire client-response.sign-arvo)
==
?+ +<.sign-arvo (on-arvo:def wir sign-arvo)
%http-response
(handle-rpc-response wir client-response.sign-arvo)
==
[cards this]
::
++ do-ping
^- card
=/ act=action [%ping ~]
:* %pass /ping/[(scot %da now.bowl)] %agent
[our.bowl %btc-provider] %poke
%btc-provider-action !>(act)
==
::
:: Handles HTTP responses from RPC servers. Parses for errors,
:: then handles response. For actions that require collating multiple
:: RPC calls, uses req-card to call out to RPC again if more
:: information is required.
++ handle-rpc-response
|= [=wire response=client-response:iris]
^- (quip card _state)
?. ?=(%finished -.response) `state
=* status status-code.response-header.response
:: handle error types: connection errors, RPC errors (in order)
::
=^ conn-err state
(connection-error status)
?^ conn-err
:_ state(connected.host-info %.n)
:~ (send-status:hc [%disconnected ~] ~)
(send-update:hc [%| u.conn-err] ~)
==
::
%+ handle-rpc-result wire
%- parse-result:rpc:bl
(get-rpc-response:bl response)
::
++ handle-rpc-result
|= [=wire r=result:rpc-types]
^- (quip card _state)
=/ ship=(unit ship)
(slaw %p (snag 1 wire))
?+ -.wire ~|("Unexpected HTTP response" !!)
%address-info
?> ?=([%get-address-info *] r)
:_ state
~[(send-update:hc [%.y %address-info +.r] ship)]
::
%tx-info
?> ?=([%get-tx-vals *] r)
:_ state
~[(send-update:hc [%.y %tx-info +.r] ship)]
::
%raw-tx
?> ?=([%get-raw-tx *] r)
:_ state
~[(send-update:hc [%.y %raw-tx +.r] ship)]
::
%broadcast-tx
?> ?=([%broadcast-tx *] r)
:_ state
~[(send-update:hc [%.y %broadcast-tx +.r] ship)]
::
%ping
?> ?=([%get-block-info *] r)
:_ state(connected.host-info %.y, block.host-info block.r)
:_ ~
%- send-status:hc
:_ ~
?: =(block.host-info block.r)
[%connected network.host-info block.r fee.r]
[%new-block network.host-info block.r fee.r blockhash.r blockfilter.r]
::
%block-info
?> ?=([%get-block-info *] r)
:_ state
~[(send-update:hc [%.y %block-info network.host-info +.r] ship)]
==
::
++ connection-error
|= status=@ud
^- [(unit error) _state]
?+ status [`[%rpc-error ~] state]
%200 [~ state]
%400 [`[%bad-request status] state]
%401 [`[%no-auth status] state(connected.host-info %.n)]
%502 [`[%not-connected status] state(connected.host-info %.n)]
%504 [`[%not-connected status] state(connected.host-info %.n)]
==
--
::
++ on-peek
~/ %on-peek
|= pax=path
^- (unit (unit cage))
?+ pax (on-peek:def pax)
@ -115,7 +332,7 @@
``noun+!>((is-whitelisted:hc (ship (slav %p +>-.pax))))
::
[%x %is-client @t ~]
``noun+!>((is-client (ship (slav %p +>-.pax))))
``noun+!>((is-client:hc (ship (slav %p +>-.pax))))
==
::
++ on-leave on-leave:def
@ -123,195 +340,32 @@
++ on-fail on-fail:def
--
:: helper core
~% %btc-provider-helper ..card ~
|_ =bowl:gall
++ handle-command
|= comm=command
^- (quip card _state)
?- -.comm
%set-credentials
:- :~ do-ping
(start-ping-timer ~s30)
==
%= state
host-info
[api-url.comm connected=%.n network.comm block=0 clients=*(set ship)]
==
::
%add-whitelist
?- -.wt.comm
%public
`state(public.whitelist %.y)
::
%kids
`state(kids.whitelist %.y)
::
%users
`state(users.whitelist (~(uni in users.whitelist) users.wt.comm))
::
%groups
`state(groups.whitelist (~(uni in groups.whitelist) groups.wt.comm))
==
::
%remove-whitelist
=. state
?- -.wt.comm
%public
state(public.whitelist %.n)
::
%kids
state(kids.whitelist %.n)
::
%users
state(users.whitelist (~(dif in users.whitelist) users.wt.comm))
::
%groups
state(groups.whitelist (~(dif in groups.whitelist) groups.wt.comm))
==
clean-client-list
==
:: if not connected, only %ping action is allowed
::
++ handle-action
|= act=action
^- (quip card _state)
?. ?|(connected.host-info ?=(%ping -.act))
~& >>> "Not connected to RPC"
[~[(send-update [%| %not-connected 500])] state]
::
=/ ract=action:rpc-types
?- -.act :: ~|("Invalid action" !!)
%address-info
[%get-address-info address.act]
::
%tx-info
[%get-tx-vals txid.act]
::
%raw-tx
[%get-raw-tx txid.act]
::
%broadcast-tx
[%broadcast-tx rawtx.act]
::
%ping
[%get-block-info ~]
::
%block-info
[%get-block-info block.act]
==
[~[(req-card act ract)] state]
::
++ req-card
|= [act=action ract=action:rpc-types]
=| out=outbound-config:iris
=/ req=request:http
(gen-request:bl host-info ract)
[%pass (rpc-wire act) %arvo %i %request req out]
:: wire structure: /action-tas/now
::
++ rpc-wire
|= act=action ^- wire
/[-.act]/[(scot %ux (cut 3 [0 20] eny.bowl))]
::
++ kick-client
|= client=ship
^- (quip card _state)
~& >>> "dropping client {<client>}"
:- ~[[%give %kick ~[/clients] `client]]
state(clients.host-info (~(dif in clients.host-info) (silt ~[client])))
::
:: Handles HTTP responses from RPC servers. Parses for errors, then handles response.
:: For actions that require collating multiple RPC calls, uses req-card to call out
:: to RPC again if more information is required.
::
++ handle-rpc-response
|= [=wire response=client-response:iris]
^- (quip card _state)
?. ?=(%finished -.response) `state
=* status status-code.response-header.response
:: handle error types: connection errors, RPC errors (in order)
::
=^ conn-err state
(connection-error status)
?^ conn-err
:_ state(connected.host-info %.n)
~[(send-status [%disconnected ~]) (send-update [%| u.conn-err])]
::
%+ handle-rpc-result wire
%- parse-result:rpc:bl
(get-rpc-response:bl response)
::
++ connection-error
|= status=@ud
^- [(unit error) _state]
?+ status [`[%rpc-error ~] state]
%200
[~ state]
%400
[`[%bad-request status] state]
%401
[`[%no-auth status] state(connected.host-info %.n)]
%502
[`[%not-connected status] state(connected.host-info %.n)]
%504
[`[%not-connected status] state(connected.host-info %.n)]
==
::
++ handle-rpc-result
|= [=wire r=result:rpc-types]
^- (quip card _state)
?+ -.wire ~|("Unexpected HTTP response" !!)
%address-info
?> ?=([%get-address-info *] r)
:_ state
~[(send-update [%.y %address-info +.r])]
::
%tx-info
?> ?=([%get-tx-vals *] r)
:_ state
~[(send-update [%.y %tx-info +.r])]
::
%raw-tx
?> ?=([%get-raw-tx *] r)
:_ state
~[(send-update [%.y %raw-tx +.r])]
::
%broadcast-tx
?> ?=([%broadcast-tx *] r)
:_ state
~[(send-update [%.y %broadcast-tx +.r])]
::
%ping
?> ?=([%get-block-info *] r)
:_ state(connected.host-info %.y, block.host-info block.r)
?: =(block.host-info block.r)
~[(send-status [%connected network.host-info block.r fee.r])]
~[(send-status [%new-block network.host-info block.r fee.r blockhash.r blockfilter.r])]
::
%block-info
?> ?=([%get-block-info *] r)
:_ state
~[(send-update [%.y %block-info network.host-info +.r])]
==
::
++ send-status
|= =status ^- card
|= [=status ship=(unit ship)]
^- card
%- ?: ?=(%new-block -.status)
~&(>> "%new-block: {<block.status>}" same)
same
[%give %fact ~[/clients] %btc-provider-status !>(status)]
=- [%give %fact ~[-] %btc-provider-status !>(status)]
?~ ship /clients
/clients/(scot %p u.ship)
::
++ send-update
|= =update
|= [=update ship=(unit ship)]
^- card
=+ c=[%give %fact ~[/clients] %btc-provider-update !>(update)]
?: ?=(%.y -.update)
:: ~& >> "prov. update: {<p.update>}"
c
~& >> "prov. err: {<p.update>}"
c
%- ?: ?=(%.y -.update)
same
~&(>> "prov. err: {<p.update>}" same)
=- [%give %fact ~[-] %btc-provider-update !>(update)]
?~ ship /clients
/clients/(scot %p u.ship)
::
++ is-whitelisted
|= user=ship ^- ?
~/ %is-whitelisted
|= user=ship
^- ?
|^
?| public.whitelist
=(our.bowl user)
@ -319,8 +373,10 @@
(~(has in users.whitelist) user)
in-group
==
::
++ is-kid
=(our.bowl (sein:title our.bowl now.bowl user))
::
++ in-group
=/ gs ~(tap in groups.whitelist)
|-
@ -328,35 +384,15 @@
?: (~(is-member groupl bowl) user i.gs)
%.y
$(gs t.gs)
:: .^((unit group:g) %gx ;:(weld /=group-store=/groups p /noun))
--
:: +clean-client-list: remove clients who are no longer whitelisted
:: called after a whitelist change
::
++ clean-client-list
^- (quip card _state)
=/ to-kick=(set ship)
%- silt
%+ murn ~(tap in clients.host-info)
|= c=ship ^- (unit ship)
?:((is-whitelisted c) ~ `c)
:_ state(clients.host-info (~(dif in clients.host-info) to-kick))
%+ turn ~(tap in to-kick)
|=(c=ship [%give %kick ~[/clients] `c])
::
++ is-client
|= user=ship ^- ?
|= user=ship
^- ?
(~(has in clients.host-info) user)
::
++ start-ping-timer
|= interval=@dr ^- card
[%pass /ping-timer %arvo %b %wait (add now.bowl interval)]
::
++ do-ping
|= interval=@dr
^- card
=/ act=action [%ping ~]
:* %pass /ping/[(scot %da now.bowl)] %agent
[our.bowl %btc-provider] %poke
%btc-provider-action !>(act)
==
[%pass /block-ping %arvo %b %wait (add now.bowl interval)]
--

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,6 @@
<div id="portal-root"></div>
<script src="/~landscape/js/channel.js"></script>
<script src="/~landscape/js/session.js"></script>
<script src="/~btc/js/bundle/index.f7ab13b7db3ec1f8b55a.js"></script>
<script src="/~btc/js/bundle/index.3e8bcc150ebd820dd3b2.js"></script>
</body>
</html>

View File

@ -13,16 +13,18 @@
::
+$ state-0 [%0 base-state-0]
+$ state-1 [%1 base-state-0]
+$ state-2 [%2 base-state-0]
+$ versioned-state
$% state-0
state-1
state-2
==
+$ card card:agent:gall
+$ nodes (map index:store node:store)
++ orm orm:store
--
::
=| state-1
=| state-2
=* state -
%- agent:dbug
^- agent:gall
@ -90,12 +92,23 @@
::
++ on-save !>(state)
++ on-load
|= =vase
|= =old=vase
^- (quip card _this)
=+ !<(old=versioned-state vase)
?: ?=(%1 -.old) `this(state old)
:_ this(state [%1 +.old])
(poke-self:pass noun+!>(%reinit))^~
=+ !<(old=versioned-state old-vase)
=| cards=(list card)
|-
?- -.old
%0
%_($ -.old %1)
%1
%_ $
-.old %2
cards (weld cards (poke-our:pass %goad noun+!>(%force))^~)
==
%2
:_ this(state old)
(weld cards (poke-self:pass noun+!>(%reinit))^~)
==
::
++ on-poke
|= [=mark =vase]

View File

@ -12,8 +12,8 @@
[%glob =glob:glob]
==
::
+$ state-3
$: %3
+$ state-4
$: %4
=configuration:srv
=serving
==
@ -22,7 +22,7 @@
%+ verb |
%- agent:dbug
::
=| state-3
=| state-4
=* state -
^- agent:gall
|_ =bowl:gall
@ -42,6 +42,7 @@
==
:~ (connect /)
(connect /'~landscape')
[%pass /serve-who %arvo %e %serve [~ /who] %home /gen/who/hoon ~]
==
::
++ connect
@ -56,6 +57,7 @@
^- (quip card _this)
|^
=+ !<(old-state=versioned-state old-vase)
=| cards=(list card)
=? old-state ?=(%0 -.old-state)
%= old-state
- %1
@ -79,16 +81,23 @@
^- [^content ? ?]
[content public %.y]
==
?> ?=(%3 -.old-state)
[~ this(state old-state)]
=? cards ?=(%3 -.old-state)
:_ cards
[%pass /serve-who %arvo %e %serve [~ /who] %home /gen/who/hoon ~]
=? old-state ?=(%3 -.old-state)
old-state(- %4)
?> ?=(%4 -.old-state)
[cards this(state old-state)]
::
+$ serving-0 (map url-base=path [=clay=path public=?])
+$ serving-1 (map url-base=path [=content public=?])
+$ serving-3 (map url-base=path [=content public=? single-page=?])
+$ versioned-state
$% state-0
[%1 state-1]
[%2 state-1]
state-3
state-4
==
::
+$ state-0
@ -100,6 +109,11 @@
$: =configuration:srv
serving=serving-1
==
+$ state-3
$: %3
=configuration:srv
serving=serving-3
==
--
::
++ on-poke
@ -205,30 +219,35 @@
?~ ext.req-line site.req-line
(snoc site.req-line u.ext.req-line)
=/ content=(unit [=content suffix=path public=?])
(get-content pax is-file)
(match-content-path pax is-file)
?~ content [not-found:gen %.n]
?- -.content.u.content
%clay
=/ scry-path=path
=/ scry-start=path
:* (scot %p our.bowl)
q.byk.bowl
(scot %da now.bowl)
(lowercase (weld path.content.u.content suffix.u.content))
path.content.u.content
==
=/ scry-path=path
(weld scry-start (lowercase suffix.u.content))
=? scry-path !.^(? %cu scry-path)
(weld scry-start /index/html)
?. .^(? %cu scry-path) [not-found:gen %.n]
?: ?=([~ %woff2] ext.req-line)
:_ public.u.content
[[200 [['content-type' '/font/woff2'] ~]] `.^(octs %cx scry-path)]
=/ file (as-octs:mimes:html .^(@ %cx scry-path))
:_ public.u.content
?+ ext.req-line not-found:gen
[~ %js] (js-response:gen file)
[~ %css] (css-response:gen file)
[~ %png] (png-response:gen file)
[~ %svg] (svg-response:gen file)
[~ %ico] (ico-response:gen file)
=/ ext (rear scry-path)
?+ ext not-found:gen
%js (js-response:gen file)
%css (css-response:gen file)
%png (png-response:gen file)
%svg (svg-response:gen file)
%ico (ico-response:gen file)
::
[~ %html]
%html
%. file
%* . html-response:gen
cache
@ -262,17 +281,8 @@
char
(add char ^~((sub 'a' 'A')))
::
++ get-content
|= [pax=path is-file=?]
^- (unit [content path ?])
=/ first-try (match-content-path pax (~(del by serving) /) is-file)
?^ first-try first-try
=/ root (~(get by serving) /)
?~ root ~
(match-content-path pax (~(gas by *^serving) [[/ u.root] ~]) is-file)
::
++ match-content-path
|= [pax=path =^serving is-file=?]
|= [pax=path is-file=?]
^- (unit [content path ?])
%+ roll
%+ sort ~(tap by serving)
@ -338,6 +348,13 @@
[%x %clay %base %hash ~]
=/ versions (base-hash:version [our now]:bowl)
``hash+!>(?~(versions 0v0 (end [0 25] i.versions)))
::
[%x %our ~]
``json+!>(s+(scot %p our.bowl))
::
[%x %url *]
=/ url t.t.path
``noun+!>((~(has by serving) url))
==
++ on-agent on-agent:def
++ on-fail on-fail:def

View File

@ -5,8 +5,8 @@
/- glob, *resource
/+ default-agent, verb, dbug
|%
++ landscape-hash 0v4.3us6c.ma3il.h5bch.qacg3.70qjl
++ btc-wallet-hash 0v1.9p61c.bd4vn.deevh.0ldbq.fkqo3
++ landscape-hash 0v4.qs4qf.3bam7.736sg.0poq8.c6vhq
++ btc-wallet-hash 0v7.v4dng.o33qi.kc497.5jc02.ke5es
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
+$ state-1 [%1 =globs:glob]
+$ all-states

View File

@ -180,10 +180,7 @@
==
::
++ add-nodes
|= $: =time
=resource:store
nodes=(map index:store node:store)
==
|= [=time =resource:store nodes=(map index:store node:store)]
^- (quip card _state)
|^
=/ [=graph:store mark=(unit mark:store)]
@ -618,392 +615,283 @@
~/ %graph-store-peek
|= =path
^- (unit (unit cage))
|^
?> (team:title our.bowl src.bowl)
?+ path (on-peek:def path)
[%x %graph-mark @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ result=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ result [~ ~]
``noun+!>(`(unit mark)`q.u.result)
?+ path (on-peek:def path)
[%x %export ~] ``noun+!>(state)
::
[%x %keys ~]
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%keys ~(key by graphs)]])
::
[%x %tags ~]
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%tags ~(key by tag-queries)]])
::
[%x %tag-queries ~]
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%tag-queries tag-queries]])
::
[%x %graph @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ result=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ result [~ ~]
[%x %tag-queries *]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
[%add-graph [ship term] `graph:store`p.u.result q.u.result %.y]
?+ t.t.path (on-peek:def path)
~ [%tag-queries tag-queries]
[%tags ~] [%tags ~(key by tag-queries)]
==
::
:: note: near-duplicate of /x/graph
::
[%x %archive @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ result=(unit marked-graph:store)
(~(get by archive) [ship term])
?~ result
~& no-archived-graph+[ship term]
[~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
[%add-graph [ship term] `graph:store`p.u.result q.u.result %.y]
::
[%x %export ~]
``noun+!>(state)
::
[%x %graph-subset @ @ @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ start=(unit atom) (rush i.t.t.t.t.path dem:ag)
=/ end=(unit atom) (rush i.t.t.t.t.t.path dem:ag)
=/ graph=(unit marked-graph:store)
=/ marked-graph=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ graph [~ ~]
?~ marked-graph [~ ~]
=* graph p.u.marked-graph
=* mark q.u.marked-graph
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
[ship term]
%- ~(gas by *(map index:store node:store))
%+ turn (tap:orm `graph:store`(lot:orm p.u.graph start end))
|= [=atom =node:store]
^- [index:store node:store]
[~[atom] node]
!>(`update:store`[now.bowl [%add-graph [ship term] graph mark %.y]])
::
[%x %node-exists @ @ @ *]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ =index:store
(turn t.t.t.t.path (cury slav %ud))
=/ node=(unit node:store)
(get-node ship term index)
``noun+!>(`?`?=(^ node))
::
[%x %node @ @ @ *]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ =index:store
(turn t.t.t.t.path (cury slav %ud))
=/ node=(unit node:store) (get-node ship term index)
?~ node [~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
[ship term]
(~(gas by *(map index:store node:store)) [index u.node] ~)
::
[%x %node-siblings ?(%older %younger) @ @ @ *]
|^
=/ older ?=(%older i.t.t.path)
=/ =ship (slav %p i.t.t.t.path)
=/ =term i.t.t.t.t.path
=/ count (slav %ud i.t.t.t.t.t.path)
=/ =index:store
(turn t.t.t.t.t.t.path (cury slav %ud))
=/ parent=index:store
(scag (dec (lent index)) index)
=/ graph
(get-node-children ship term parent)
?~ graph [~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
[ship term]
%- ~(gas by *(map index:store node:store))
%+ turn
?: older
(tab:orm u.graph `(rear index) count)
:: TODO time complexity not desirable for %younger case
::
%+ slag (safe-sub (lent -) count)
%- tap:orm
%+ lot:orm u.graph
[~ `(snag (dec (lent index)) index)]
|= [=atom =node:store]
^- [index:store node:store]
[(snoc parent atom) node]
[%x %update-log @ @ *]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ update-log
(~(get by update-logs) [ship term])
?~ update-log [~ ~]
:- ~ :- ~ :- %noun
!>
?+ t.t.t.t.path (on-peek:def path)
~ `update-log:store`u.update-log
::
++ safe-sub
|= [a=@ b=@]
^- @
?: (gte b a)
0
(sub a b)
--
[%latest ~]
^- (unit time)
%+ biff update-log
|= =update-log:store
(bind (pry:orm-log:store update-log) head)
::
[%subset @ @ ~]
^- update-log:store
=* start i.t.t.t.t.t.path
=* end i.t.t.t.t.t.t.path
%^ lot:orm-log
u.update-log
(slaw %da start)
(slaw %da end)
==
::
[%x %shallow-children @ @ *]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ =index:store
(turn t.t.t.t.path (cury slav %ud))
=/ children
(get-node-children ship term index)
?~ children [~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:+ now.bowl %add-nodes
:- [ship term]
%- ~(gas by *(map index:store node:store))
%+ turn (tap:orm u.children)
|= [=atom =node:store]
^- [index:store node:store]
:- (snoc index atom)
node(children [%empty ~])
::
[%x ?(%newest %oldest) @ @ @ *]
=/ newest ?=(%newest i.t.path)
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ count=@ud
(slav %ud i.t.t.t.t.path)
=/ =index:store
(turn t.t.t.t.t.path (cury slav %ud))
=/ children
(get-node-children ship term index)
?~ children [~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
[ship term]
%- ~(gas by *(map index:store node:store))
%+ turn
%+ scag count
?: newest
(tap:orm u.children)
(bap:orm u.children)
|= [=atom =node:store]
^- [index:store node:store]
[(snoc index atom) node]
::
[%x %node-children-subset @ @ @ @ @ *]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ start=(unit atom) (rush i.t.t.t.t.path dem:ag)
=/ end=(unit atom) (rush i.t.t.t.t.t.path dem:ag)
=/ =index:store
(turn t.t.t.t.t.t.path |=(=cord (slav %ud cord)))
=/ node=(unit node:store) (get-node ship term index)
?~ node [~ ~]
?- -.children.u.node
%empty [~ ~]
%graph
[%x %graph @ @ *]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ marked-graph=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ marked-graph [~ ~]
=* graph p.u.marked-graph
=* mark q.u.marked-graph
?+ t.t.t.t.path (on-peek:def path)
~
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%add-graph [ship term] graph mark %.y]])
::
[%mark ~]
``noun+!>(`(unit ^mark)`mark)
::
[%subset ?(%lone %kith) @ @ ~]
=/ start=(unit atom) (rush i.t.t.t.t.t.t.path dem:ag)
=/ end=(unit atom) (rush i.t.t.t.t.t.t.t.path dem:ag)
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
[ship term]
:^ now.bowl %add-nodes [ship term]
%- ~(gas by *(map index:store node:store))
%+ turn (tap:orm `graph:store`(lot:orm p.children.u.node end start))
%+ turn (tap:orm (lot:orm graph start end))
|= [=atom =node:store]
^- [index:store node:store]
[(snoc index atom) node]
==
::
[%x %deep-nodes-older-than @ @ @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ count=(unit atom) (rush i.t.t.t.t.path dem:ag)
=/ start=(unit atom) (rush i.t.t.t.t.t.path dem:ag)
?: ?=(~ count)
[~ ~]
=/ result=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ result
[~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
[ship term]
=* a u.count
=/ b=(list (pair atom node:store))
(tab:orm p.u.result start u.count)
=| c=index:store
=| d=(map index:store node:store)
=| e=@ud
=- d
|- ^- [e=@ud d=(map index:store node:store)]
?: ?|(?=(~ b) =(e a))
[e d]
=* atom p.i.b
=* node q.i.b
=. c (snoc c atom)
?- -.children.node
%empty
$(b t.b, e +(e), d (~(put by d) c node), c (snip c))
:- atom^~
?: ?=(%kith i.t.t.t.t.t.path)
node
node(children [%empty ~])
::
%graph
=/ f $(b (tab:orm p.children.node ~ (sub a e)))
?: =(e.f a) f
%_ $
b t.b
e +(e.f)
d (~(put by d.f) c node(children [%empty ~]))
c (snip c)
==
==
::
[%x %firstborn @ @ @ *]
|^
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ =index:store
(turn t.t.t.t.path (cury slav %ud))
?> ?=(^ index)
=/ result=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ result
[~ ~]
%- (bond |.(`(unit (unit cage))`[~ ~]))
%+ biff
(collect-parents p.u.result index ship term)
(corl some collect-firstborn)
::
++ collect-parents
|= [=graph:store =index:store =ship =term]
^- %- unit
[node:store index:store (map index:store node:store) ^ship ^term]
=| =(map index:store node:store)
=| =node:store
=| ind=index:store
=/ len (lent index)
|-
?: (gte (lent ind) len)
`[node ind map ship term]
?> ?=(^ index)
=* atom i.index
?. (has:orm graph atom)
~
=: node (got:orm graph atom)
ind (snoc ind atom)
==
?: ?=(%empty -.children.node)
?. (gte (lent ind) len)
~
:- ~
:* node ind
(~(put by map) ind node)
ship term
==
%_ $
index t.index
graph p.children.node
map (~(put by map) ind node(children empty+~))
==
::
++ collect-firstborn
|= [=node:store =index:store mp=(map index:store node:store) =ship =term]
^- (unit (unit cage))
?: ?=(%empty -.children.node)
[%node *]
|^
=* pax t.t.t.t.t.path
?+ pax (on-peek:def path)
[%exists ^]
=/ =index:store
(turn t.pax (cury slav %ud))
=/ node (get-node graph index)
``noun+!>(`?`?=(^ node))
::
[%index ?(%lone %kith) ^]
=/ =index:store
(turn t.t.pax (cury slav %ud))
=/ node (get-node graph index)
?~ node [~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
[now.bowl [%add-nodes [ship term] mp]]
=/ item=[k=atom v=node:store]
(need (ram:orm p.children.node))
=. index (snoc index k.item)
$(mp (~(put by mp) index v.item(children empty+~)), node v.item)
--
::
[%x %update-log-subset @ @ @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ start=(unit time) (slaw %da i.t.t.t.t.path)
=/ end=(unit time) (slaw %da i.t.t.t.t.t.path)
=/ update-log=(unit update-log:store) (~(get by update-logs) [ship term])
?~ update-log [~ ~]
:: orm-log is ordered backwards, so swap start and end
``noun+!>(`update-log:store`(lot:orm-log u.update-log end start))
::
[%x %update-log @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ update-log=(unit update-log:store) (~(get by update-logs) [ship term])
?~ update-log [~ ~]
``noun+!>(`update-log:store`u.update-log)
::
[%x %peek-update-log @ @ ~]
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ m-update-log=(unit update-log:store)
(~(get by update-logs) [ship term])
:- ~ :- ~ :- %noun
!> ^- (unit time)
%+ biff m-update-log
|= =update-log:store
=/ result=(unit [=time =update:store])
(pry:orm-log:store update-log)
(bind result head)
==
::
++ get-node-children
|= [=ship =term =index:store]
^- (unit graph:store)
?: ?=(~ index)
=/ graph
(~(get by graphs) [ship term])
?~ graph ~
`p.u.graph
=/ node
(get-node ship term index)
?~ node ~
?: ?=(%empty -.children.u.node)
~
`p.children.u.node
::
++ get-node
|= [=ship =term =index:store]
^- (unit node:store)
=/ parent-graph=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ parent-graph ~
=/ node=(unit node:store) ~
=/ =graph:store p.u.parent-graph
|-
?~ index
node
?~ t.index
(get:orm graph i.index)
=. node (get:orm graph i.index)
?~ node ~
?- -.children.u.node
%empty ~
%graph $(graph p.children.u.node, index t.index)
:^ now.bowl %add-nodes [ship term]
%- ~(gas by *(map index:store node:store))
:_ ~ :- index
?: ?=(%kith i.t.pax) u.node
u.node(children [%empty ~])
::
[%children ?(%lone %kith) @ @ *]
=/ start=(unit atom) (rush i.t.t.path dem:ag)
=/ end=(unit atom) (rush i.t.t.t.path dem:ag)
=/ =index:store
(turn t.t.t.t.pax (cury slav %ud))
=/ node (get-node graph index)
?: ?& ?=(~ node)
?=(^ index)
==
[~ ~]
=/ children=graph:store
?~ node
graph
?: ?=(%empty -.children.u.node)
~
p.children.u.node
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:^ now.bowl %add-nodes [ship term]
%- ~(gas by *(map index:store node:store))
%+ turn (tap:orm (lot:orm children end start))
|= [=atom =node:store]
^- [index:store node:store]
:- (snoc index atom)
?: ?=(%kith i.t.pax) node
node(children [%empty ~])
::
[%siblings ?(%older %newer %oldest %newest) ?(%lone %kith) @ *]
=/ count (slav %ud i.t.t.t.pax)
=/ =index:store
(turn t.t.t.t.pax (cury slav %ud))
=/ parent=index:store (snip index)
=/ node
(get-node graph ?:(?=(?(%oldest %newest) i.t.pax) index parent))
=/ children=graph:store
?~ node
graph
?: ?=(%empty -.children.u.node)
~
p.children.u.node
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:^ now.bowl %add-nodes [ship term]
%- ~(gas by *(map index:store node:store))
%+ turn
?- i.t.pax
%oldest (scag count (bap:orm children))
%older (tab:orm children `(rear index) count)
%newest (scag count (tap:orm children))
::
%newer
%+ slag (safe-sub (lent -) count)
(tap:orm (lot:orm children ~ `(rear index)))
==
|= [=atom =node:store]
^- [index:store node:store]
:- %- snoc
:_ atom
?:(?=(?(%newest %oldest) i.t.pax) index parent)
?: ?=(%kith i.t.t.pax) node
node(children [%empty ~])
::
[%firstborn ^]
|^
=/ =index:store
(turn t.pax (cury slav %ud))
%- (bond |.(`(unit (unit cage))`[~ ~]))
%+ biff
(collect-parents graph index)
(corl some collect-firstborn)
::
++ collect-parents
|= [=graph:store =index:store]
^- (unit [node:store index:store (map index:store node:store)])
=| =(map index:store node:store)
=| =node:store
=| ind=index:store
=/ len (lent index)
|-
?: (gte (lent ind) len)
`[node ind map]
?> ?=(^ index)
=* atom i.index
?. (has:orm graph atom)
~
=: node (got:orm graph atom)
ind (snoc ind atom)
==
?: ?=(%empty -.children.node)
?. (gte (lent ind) len)
~
`[node ind (~(put by map) ind node)]
%_ $
index t.index
graph p.children.node
map (~(put by map) ind node(children empty+~))
==
::
++ collect-firstborn
|= [=node:store =index:store =(map index:store node:store)]
^- (unit (unit cage))
?: ?=(%empty -.children.node)
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%add-nodes [ship term] map]])
=/ item=[k=atom v=node:store]
(need (ram:orm p.children.node))
=. index (snoc index k.item)
$(map (~(put by map) index v.item(children empty+~)), node v.item)
--
==
::
++ get-node
|= [=graph:store =index:store]
^- (unit node:store)
=| node=(unit node:store)
|-
?~ index node
?~ t.index (get:orm graph i.index)
=. node (get:orm graph i.index)
?~ node ~
?: ?=(%empty -.children.u.node)
~
$(graph p.children.u.node, index t.index)
::
++ safe-sub
|= [a=@ b=@]
^- @
?:((gte b a) 0 (sub a b))
--
::
[%depth-first @ @ ~]
=/ count=(unit atom) (rush i.t.t.t.t.path dem:ag)
=/ start=(unit atom) (rush i.t.t.t.t.t.path dem:ag)
?: ?=(~ count)
[~ ~]
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:^ now.bowl %add-nodes [ship term]
=* a u.count
=/ b=(list (pair atom node:store))
(tab:orm graph start u.count)
=| c=index:store
=| d=(map index:store node:store)
=| e=@ud
=- d
|- ^- [e=@ud d=(map index:store node:store)]
?: ?|(?=(~ b) =(e a))
[e d]
=* atom p.i.b
=* node q.i.b
=. c (snoc c atom)
?- -.children.node
%empty
$(b t.b, e +(e), d (~(put by d) c node), c (snip c))
::
%graph
=/ f $(b (tab:orm p.children.node ~ (sub a e)))
?: =(e.f a) f
%_ $
b t.b
e +(e.f)
d (~(put by d.f) c node(children [%empty ~]))
c (snip c)
==
==
==
--
::
++ on-arvo
|= [=wire =sign-arvo]
^- (quip card _this)
?+ wire (on-arvo:def wire sign-arvo)
::
:: old wire, do nothing
[%graph *] [~ this]
[%validator @ ~] [~ this]
[%try-rejoin @ *] [~ this]
==
::
++ on-arvo on-arvo:def
++ on-agent on-agent:def
++ on-leave on-leave:def
++ on-fail on-fail:def

View File

@ -127,8 +127,13 @@
++ hide
|= rid=resource
^- (quip card _state)
=/ =request:view (~(got by joining) rid)
?: ?=(final:view progress.request)
=. joining (~(del by joining) rid)
:_ state
(fact:io group-view-update+!>(`update:view`[%initial joining]) /all ~)^~
:- (fact:io group-view-update+!>([%hide rid]) /all ~)^~
state(joining (~(jab by joining) rid |=(request:view +<(hidden %.y))))
state(joining (~(put by joining) rid request(hidden %.y)))
::
++ has-joined
|= rid=resource
@ -160,7 +165,7 @@
++ tx-progress
|= =progress:view
=. joining
(~(jab by joining) rid |=(request:view +<(progress progress)))
(~(jab by joining) rid |=(req=request:view req(progress progress)))
=; =cage
(emit (fact:io cage /all tx+(en-path:resource rid) ~))
group-view-update+!>([%progress rid progress])
@ -217,10 +222,11 @@
?> ?=(%poke-ack -.sign)
?^ p.sign
(cleanup %no-perms)
=> %- emit
%+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook
pull-hook-action+!>([%add ship rid])
(tx-progress %added)
=. jn-core
(tx-progress %added)
%- emit
%+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook
pull-hook-action+!>([%add ship rid])
::
%pull-groups
?> ?=(%poke-ack -.sign)
@ -283,7 +289,7 @@
::
++ md-fact
|= [=mark =vase]
?. ?=(%metadata-update-1 mark) jn-core
?. ?=(%metadata-update-2 mark) jn-core
=+ !<(=update:metadata vase)
?. ?=(%initial-group -.update) jn-core
?. =(group.update rid) jn-core
@ -324,7 +330,6 @@
|= =progress:view
=. jn-core
(tx-progress progress)
=. joining (~(del by joining) rid)
=. jn-core
(emit (leave-our:(jn-pass-io /groups) %group-store))
(emit (leave-our:(jn-pass-io /md) %metadata-store))

View File

@ -285,7 +285,7 @@
^- $-(indexed-post:graph-store (unit notif-kind:hook))
=+ %^ scry [our now]:bowl
,mark=(unit mark)
/gx/graph-store/graph-mark/(scot %p entity.rid)/[name.rid]/noun
/gx/graph-store/graph/(scot %p entity.rid)/[name.rid]/mark/noun
?~ mark
|=(=indexed-post:graph-store ~)
(scry-notif-conversion [our now]:bowl q.byk.bowl u.mark)

View File

@ -113,7 +113,7 @@
(group-update !<(update:group-store q.cage.sign))
[cards this]
::
%metadata-update-1
%metadata-update-2
=^ cards state
(metadata-update !<(update:metadata q.cage.sign))
[cards this]

View File

@ -2,7 +2,7 @@
/+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln
|%
+$ state
$: %14
$: %16
drum=state:drum
helm=state:helm
kiln=state:kiln
@ -10,13 +10,15 @@
+$ any-state
$% state
[ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)]
[%7 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%8 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%9 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%10 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%11 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%12 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%13 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%7 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%8 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%9 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%10 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%11 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%12 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%13 drum=any-state:drum helm=state:helm kiln=state-1:kiln]
[%14 drum=any-state:drum helm=state:helm kiln=state:kiln]
[%15 drum=any-state:drum helm=state:helm kiln=state:kiln]
==
+$ any-state-tuple
$: drum=any-state:drum

View File

@ -24,6 +24,6 @@
<div id="portal-root"></div>
<script src="/~landscape/js/channel.js"></script>
<script src="/~landscape/js/session.js"></script>
<script src="/~landscape/js/bundle/index.af45eeaf465dff7d73f1.js"></script>
<script src="/~landscape/js/bundle/index.c1a890b306daa1aee34b.js"></script>
</body>
</html>

View File

@ -25,8 +25,6 @@
^- (list @tas)
:~ %group-store
%metadata-store
%contact-store
%contact-hook
%invite-store
%graph-store
==

View File

@ -38,7 +38,7 @@
update:metadata
%metadata-update
%metadata-push-hook
1 1
2 2
%.n
==
+$ state-zero
@ -180,7 +180,7 @@
%kick [watch-store^~ state]
::
%fact
?> ?=(%metadata-update-1 p.cage.sign)
?> ?=(%metadata-update-2 p.cage.sign)
=+ !<(=update:metadata q.cage.sign)
?. ?=(%initial-group -.update) `state
`state(previews (~(del by previews) group.update))
@ -325,7 +325,7 @@
%+ turn ~(tap by associations)
|= [=md-resource:metadata =association:metadata]
%+ poke-our:pass:io %metadata-store
:- %metadata-update-1
:- %metadata-update-2
!> ^- update:metadata
[%remove resource md-resource]
::

View File

@ -14,7 +14,7 @@
update:store
%metadata-update
%metadata-pull-hook
1 1
2 2
==
::
+$ agent (push-hook:push-hook config)
@ -94,7 +94,7 @@
^- (quip card (unit vase))
=/ =update:store !<(update:store vas)
:- ~
?. ?=(?(%add %remove) -.update)
?. ?=(?(%add %remove %edit) -.update)
~
=/ role=(unit (unit role-tag))
(role-for-ship:grp group.update src.bowl)

View File

@ -24,7 +24,7 @@
:: /group/%path associations for group
::
/- store=metadata-store, pull-hook
/+ default-agent, verb, dbug, resource, *migrate
/+ default-agent, verb, dbug, resource, *migrate, lib=metadata-store
|%
+$ card card:agent:gall
+$ base-state-0
@ -107,6 +107,7 @@
+$ state-9 [%9 base-state-3]
+$ state-10 [%10 base-state-3]
+$ state-11 [%11 base-state-3]
+$ state-12 [%12 base-state-3]
+$ versioned-state
$% state-0
state-1
@ -120,10 +121,11 @@
state-9
state-10
state-11
state-12
==
::
+$ inflated-state
$: state-11
$: state-12
cached-indices
==
--
@ -151,18 +153,145 @@
++ on-poke
|= [=mark =vase]
^- (quip card _this)
?> (team:title our.bowl src.bowl)
?> (team:title [our src]:bowl)
|^
=^ cards state
?+ mark (on-poke:def mark vase)
?(%metadata-action %metadata-update-1)
(poke-metadata-update:mc !<(update:store vase))
?(%metadata-action %metadata-update-2)
(poke-metadata-update !<(update:store vase))
::
%import
(poke-import:mc q.vase)
(poke-import q.vase)
::
%noun ~& +.state `state
==
[cards this]
::
++ poke-metadata-update
|= upd=update:store
^- (quip card _state)
|^
?+ -.upd ~|(%bad-poke !!)
%add (handle-add +.upd)
%remove (handle-remove +.upd)
%edit (handle-edit +.upd)
%initial-group (handle-initial-group +.upd)
==
::
++ handle-add
|= [group=resource =md-resource:store =metadatum:store]
^- (quip card _state)
:- %- send-diff:mc
[%add group md-resource metadatum]
%= state
associations
(~(put by associations) md-resource [group metadatum])
::
app-indices
%+ ~(put ju app-indices)
app-name.md-resource
[group resource.md-resource]
::
resource-indices
(~(put by resource-indices) md-resource group)
::
group-indices
(~(put ju group-indices) group md-resource)
==
::
++ handle-edit
|= [group=resource =md-resource:store =edit-field:store]
^- (quip card _state)
=/ [new-group=resource =metadatum:store]
~| %no-assoc-for-edit
(~(got by associations) md-resource)
~| %cant-reassign-groups
?> =(new-group group)
=. metadatum
?- -.edit-field
%title metadatum(title title.edit-field)
%description metadatum(description description.edit-field)
%color metadatum(color color.edit-field)
%picture metadatum(picture url.edit-field)
%hidden metadatum(hidden hidden.edit-field)
%preview metadatum(preview preview.edit-field)
%vip metadatum(vip vip.edit-field)
==
:- (send-diff:mc %add group md-resource metadatum)
%_ state
associations (~(put by associations) md-resource group metadatum)
==
::
++ handle-remove
|= [group=resource =md-resource:store]
^- (quip card _state)
:- (send-diff:mc [%remove group md-resource])
%= state
associations
(~(del by associations) md-resource)
::
app-indices
%+ ~(del ju app-indices)
app-name.md-resource
[group resource.md-resource]
::
resource-indices
(~(del by resource-indices) md-resource)
::
group-indices
(~(del ju group-indices) group md-resource)
==
::
++ handle-initial-group
|= [group=resource =associations:store]
=/ assocs=(list [=md-resource:store grp=resource =metadatum:store])
~(tap by associations)
:- (send-diff:mc %initial-group group associations)
|-
?~ assocs
state
=, assocs
?> =(group grp.i)
=^ cards state
(handle-add group [md-resource metadatum]:i)
$(assocs t)
--
::
++ poke-import
|= arc=*
^- (quip card _state)
|^
=^ cards state
(on-load:mc !>([%9 (remake-metadata ;;(tree-metadata +.arc))]))
:_ state
%+ weld cards
%+ turn ~(tap in ~(key by group-indices))
|= rid=resource
%- poke-our
?: =(entity.rid our.bowl)
:- %metadata-push-hook
push-hook-action+!>([%add rid])
:- %metadata-pull-hook
pull-hook-action+!>([%add [entity .]:rid])
::
++ poke-our
|= [app=term =cage]
^- card
[%pass / %agent [our.bowl app] %poke cage]
::
+$ tree-metadata
$: associations=(tree [md-resource:store [resource metadatum:store]])
~
==
::
++ remake-metadata
|= tm=tree-metadata
^- base-state-3
:* (remake-map associations.tm)
~
==
--
--
::
++ on-watch
|= =path
@ -172,7 +301,7 @@
=/ cards=(list card)
?+ path (on-watch:def path)
[%all ~]
(give %metadata-update-1 !>([%associations associations]))
(give %metadata-update-2 !>([%associations associations]))
::
[%updates ~]
~
@ -180,7 +309,7 @@
[%app-name @ ~]
=/ =app-name:store i.t.path
=/ app-indices (metadata-for-app:mc app-name)
(give %metadata-update-1 !>([%associations app-indices]))
(give %metadata-update-2 !>([%associations app-indices]))
==
[cards this]
::
@ -218,6 +347,18 @@
=/ =md-resource:store
[i.t.t.path (de-path:resource t.t.t.path)]
``noun+!>(`(unit association:store)`(~(get by associations) md-resource))
::
[%x %metadata-json @ @ @ @ ~]
=/ =md-resource:store
[i.t.t.path (de-path:resource t.t.t.path)]
=/ assoc=(unit association:store) (~(get by associations) md-resource)
?~ assoc ~
=/ =json
%- pairs:enjs:format
:~ group+s+(enjs-path:resource group.u.assoc)
metadatum+(metadatum:enjs:lib metadatum.u.assoc)
==
``json+!>(json)
::
[%x %resource @ *]
=/ app=term i.t.t.path
@ -243,7 +384,7 @@
=| cards=(list card)
|^
=* loop $
?: ?=(%11 -.old)
?: ?=(%12 -.old)
:- cards
%_ state
associations associations.old
@ -251,6 +392,8 @@
group-indices (rebuild-group-indices associations.old)
app-indices (rebuild-app-indices associations.old)
==
?: ?=(%11 -.old)
$(-.old %12, associations.old (reset-group-hidden associations.old))
?: ?=(%10 -.old)
$(-.old %11, associations.old (hide-dm-assoc associations.old))
?: ?=(%9 -.old)
@ -293,6 +436,17 @@
:: pre-breach, can safely throw away
loop(old *state-8)
::
++ reset-group-hidden
|= assoc=associations:store
^- associations:store
%- ~(gas by *associations:store)
%+ turn ~(tap by assoc)
|= [m=md-resource:store [g=resource met=metadatum:store]]
^- [md-resource:store association:store]
=? hidden.met ?=(%groups app-name.m)
%.n
[m [g met]]
::
++ hide-dm-assoc
|= assoc=associations:store
^- associations:store
@ -403,109 +557,6 @@
ship+path.md-resource
[[path [%graph new-path]] m(module app)]
--
::
:: TODO: refactor into a |^ inside the agent core
++ poke-metadata-update
|= upd=update:store
^- (quip card _state)
?> (team:title [our src]:bowl)
?+ -.upd !!
%add (handle-add +.upd)
%remove (handle-remove +.upd)
%initial-group (handle-initial-group +.upd)
==
::
:: TODO: refactor into a |^ inside the agent core
++ poke-import
|= arc=*
^- (quip card _state)
|^
=^ cards state
(on-load !>([%9 (remake-metadata ;;(tree-metadata +.arc))]))
:_ state
%+ weld cards
%+ turn ~(tap in ~(key by group-indices))
|= rid=resource
%- poke-our
?: =(entity.rid our.bowl)
:- %metadata-push-hook
push-hook-action+!>([%add rid])
:- %metadata-pull-hook
pull-hook-action+!>([%add [entity .]:rid])
::
++ poke-our
|= [app=term =cage]
^- card
[%pass / %agent [our.bowl app] %poke cage]
::
+$ tree-metadata
$: associations=(tree [md-resource:store [resource metadatum:store]])
~
==
::
++ remake-metadata
|= tm=tree-metadata
^- base-state-3
:* (remake-map associations.tm)
~
==
--
::
++ handle-add
|= [group=resource =md-resource:store =metadatum:store]
^- (quip card _state)
:- %- send-diff
[%add group md-resource metadatum]
%= state
associations
(~(put by associations) md-resource [group metadatum])
::
app-indices
%+ ~(put ju app-indices)
app-name.md-resource
[group resource.md-resource]
::
resource-indices
(~(put by resource-indices) md-resource group)
::
group-indices
(~(put ju group-indices) group md-resource)
==
::
++ handle-remove
|= [group=resource =md-resource:store]
^- (quip card _state)
:- (send-diff [%remove group md-resource])
%= state
associations
(~(del by associations) md-resource)
::
app-indices
%+ ~(del ju app-indices)
app-name.md-resource
[group resource.md-resource]
::
resource-indices
(~(del by resource-indices) md-resource)
::
group-indices
(~(del ju group-indices) group md-resource)
==
::
++ handle-initial-group
|= [group=resource =associations:store]
=/ assocs=(list [=md-resource:store grp=resource =metadatum:store])
~(tap by associations)
:- (send-diff %initial-group group associations)
|-
?~ assocs
state
=, assocs
?> =(group grp.i)
=^ cards state
(handle-add group [md-resource metadatum]:i)
$(assocs t)
::
++ metadata-for-app
|= =app-name:store
^- associations:store
@ -541,6 +592,6 @@
++ update-subscribers
|= [pax=path =update:store]
^- (list card)
[%give %fact ~[pax] %metadata-update-1 !>(update)]~
[%give %fact ~[pax] %metadata-update-2 !>(update)]~
--
--

433
pkg/arvo/app/notify.hoon Normal file
View File

@ -0,0 +1,433 @@
::
/- *notify, resource, hark-store, post
/+ default-agent, verb, dbug, group, agentio
::
|%
+$ card card:agent:gall
::
+$ provider-state (map term provider-entry)
+$ provider-entry
$: notify-endpoint=@t
binding-endpoint=@t
auth-token=@t
clients=(map ship binding=(unit @t))
=whitelist
==
::
+$ client-state
$: providers=(jug @p term)
==
::
+$ state-0
$: %0
=provider-state
=client-state
==
::
+$ versioned-state
$% state-0
==
::
--
::
=| state-0
=* state -
::
%- agent:dbug
%+ verb |
^- agent:gall
::
=<
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
do ~(. +> bowl)
io ~(. agentio bowl)
pass pass:io
::
++ on-init
:_ this
[(~(watch-our pass:io /hark) %hark-store /updates)]~
::
++ on-save !>(state)
++ on-load
|= =old=vase
^- (quip card _this)
=/ old !<(versioned-state old-vase)
?- -.old
%0
:_ this(state old)
?. (~(has by wex.bowl) [/hark our.bowl %hark-store])
~
[(~(watch-our pass:io /hark) %hark-store /updates)]~
==
::
++ on-poke
|= [=mark =vase]
^- (quip card _this)
|^
=^ cards state
?+ mark (on-poke:def mark vase)
%notify-provider-action (handle-provider-action !<(provider-action vase))
%notify-client-action (handle-client-action !<(client-action vase))
==
[cards this]
::
++ handle-provider-action
|= act=provider-action
^- (quip card _state)
?- -.act
%add
?> (team:title our.bowl src.bowl)
=/ new-entry=provider-entry
:* notify.act
binding.act
auth-token.act
~
whitelist.act
==
[~ state(provider-state (~(put by provider-state) service.act new-entry))]
::
%remove
?> (team:title our.bowl src.bowl)
=/ entry=(unit provider-entry) (~(get by provider-state) service.act)
?~ entry
~|("no such service: {<service.act>}" !!)
:_ state(provider-state (~(del by provider-state) service.act))
%+ turn ~(tap by clients.u.entry)
|= [who=@p *]
^- card
(leave-path:pass [who %notify] /notify/(scot %p who)/[service.act])
::
%client-join
=/ entry=(unit provider-entry) (~(get by provider-state) service.act)
?~ entry
~|("no such service: {<service.act>}" !!)
?. (is-whitelisted:do src.bowl u.entry)
~|("permission denied" !!)
=. clients.u.entry (~(put by clients.u.entry) src.bowl ~)
:_ state(provider-state (~(put by provider-state) service.act u.entry))
:~ %: register-binding:do
service.act
u.entry
binding-endpoint.u.entry
src.bowl
address.act
==
%+ watch:pass
[src.bowl %notify]
/notify/(scot %p src.bowl)/[service.act]
==
::
%client-leave
=/ entry=(unit provider-entry) (~(get by provider-state) service.act)
?~ entry
~|("no such service: {<service.act>}" !!)
?. (is-client:do src.bowl u.entry)
~|("permission denied" !!)
=/ client-info=(unit @t) (~(got by clients.u.entry) src.bowl)
=. clients.u.entry (~(del by clients.u.entry) src.bowl)
:_ state(provider-state (~(put by provider-state) service.act u.entry))
?~ client-info
:_ ~
%+ leave-path:pass
[src.bowl %notify]
/notify/(scot %p src.bowl)/[service.act]
:~ %: remove-binding:do
service.act
u.entry
src.bowl
binding-endpoint.u.entry
u.client-info
==
%+ leave-path:pass
[src.bowl %notify]
/notify/(scot %p src.bowl)/[service.act]
==
==
::
++ handle-client-action
|= act=client-action
^- (quip card _state)
?> (team:title our.bowl src.bowl)
?- -.act
%connect-provider
=. providers.client-state
(~(put ju providers.client-state) who.act service.act)
=/ pact=provider-action [%client-join service.act address.act]
:_ state
[(poke:pass [who.act %notify] %notify-provider-action !>(pact))]~
::
%remove-provider
=. providers.client-state
(~(del ju providers.client-state) who.act service.act)
=/ pact=provider-action [%client-leave service.act]
:_ state
[(poke:pass [who.act %notify] %notify-provider-action !>(pact))]~
==
--
::
++ on-watch
|= =path
^- (quip card _this)
?+ path (on-watch:def path)
[%notify @ @ ~]
=* service i.t.t.path
?. (~(has ju providers.client-state) src.bowl service)
~|("permission denied" !!)
`this
==
::
++ on-leave
|= =path
^- (quip card _this)
`this
::
++ on-peek on-peek:def
::
++ on-agent
|= [=wire =sign:agent:gall]
^- (quip card _this)
?+ wire (on-agent:def wire sign)
::
:: subscription from client to their own hark-store
::
[%hark ~]
?+ -.sign (on-agent:def wire sign)
%fact
:_ this
?. ?=(%hark-update p.cage.sign)
~
=+ !<(hark-update=update:hark-store q.cage.sign)
=/ notes=(list notification) (filter-notifications:do hark-update)
?~ notes
~
:: only send the last one, since hark accumulates notifcations
=/ =update [%notification `notification`(snag 0 (flop notes))]
=/ card (fact-all:io %notify-update !>(update))
(drop card)
::
%kick
:_ this
[%pass /hark %agent [our.bowl %hark-store] %watch /updates]~
==
::
:: subscription from provider to client
::
[%agentio-watch %notify @ @ ~]
=/ who (slav %p i.t.t.wire)
=* service i.t.t.t.wire
?+ -.sign (on-agent:def wire sign)
%fact
?> ?=(%notify-update p.cage.sign)
=+ !<(=update q.cage.sign)
:_ this
?- -.update
%notification
=/ entry=(unit provider-entry) (~(get by provider-state) service)
?~ entry
~
[(send-notification:do u.entry who notification.update)]~
==
::
%kick
:_ this
[(watch:pass [who %notify] /notify/(scot %p who)/[service])]~
::
%watch-ack
?~ p.sign
`this
((slog u.p.sign) `this)
==
==
::
++ on-arvo
|= [=wire =sign-arvo]
^- (quip card _this)
?+ wire (on-arvo:def wire sign-arvo)
[%register-binding @ @ @ ~]
=/ who=@p (slav %p i.t.wire)
=* service i.t.t.wire
::
?> ?=(%iris -.sign-arvo)
?> ?=(%http-response +<.sign-arvo)
?> ?=(%finished -.client-response.sign-arvo)
?> ?=(^ full-file.client-response.sign-arvo)
=/ =mime-data:iris u.full-file.client-response.sign-arvo
?> =('application/json' type.mime-data)
=/ jon=json
(fall (rush (@t q.data.mime-data) apex:de-json:html) *json)
=/ [sid=@t message=@t]
%. jon
%- ot:dejs:format
:~ sid+so:dejs:format
message+so:dejs:format
==
::
=/ entry=(unit provider-entry) (~(get by provider-state) service)
:- ~
?~ entry
this
=. clients.u.entry (~(put by clients.u.entry) who `sid)
this(provider-state (~(put by provider-state) service u.entry))
::
[%remove-binding *]
`this
::
[%send-notification *]
`this
==
::
++ on-fail on-fail:def
--
|_ bowl=bowl:gall
::
++ filter-notifications
|= =update:hark-store
^- (list notification)
?+ -.update ~
%more
(zing (turn more.update filter-notifications))
::
%added
?- -.index.update
%graph
?: =(`%graph-validator-dm mark.index.update)
?. ?=(%graph -.contents.notification.update)
~
%+ turn list.contents.notification.update
|= =post:post
^- notification
[graph.index.update index.post]
?: =(`%graph-validator-chat mark.index.update)
=/ hid (group-is-hidden graph.index.update)
?~ hid ~
?. u.hid ~
?. ?=(%graph -.contents.notification.update)
~
%+ turn list.contents.notification.update
|= =post:post
^- notification
[graph.index.update index.post]
~
::
%group ~
==
==
::
++ group-is-hidden
|= =resource:resource
^- (unit ?)
=/ grp=(unit group:group) (~(scry-group group bowl) resource)
?~ grp ~
`hidden.u.grp
::
++ is-whitelisted
|= [who=@p entry=provider-entry]
^- ?
|^
?| public.whitelist.entry
=(our.bowl who)
is-kid
(~(has in users.whitelist.entry) who)
in-group
==
::
++ is-kid
?& kids.whitelist.entry
=(our.bowl (sein:title our.bowl now.bowl who))
==
::
++ in-group
=/ gs ~(tap in groups.whitelist.entry)
|-
?~ gs %.n
?: (~(is-member group bowl) who i.gs)
%.y
$(gs t.gs)
--
::
++ is-client
|= [who=@p entry=provider-entry]
^- ?
(~(has by clients.entry) who)
::
++ post-form
|= [=wire url=@t auth=@t params=(list [@t @t])]
^- card
=/ data
%+ roll
%+ sort params
|= [[p=@t @t] [q=@t @t]]
(aor p q)
|= [[p=@t q=@t] out=_url]
(rap 3 out p q ~)
=/ hmac-sig (hmac-sha1t:hmac:crypto auth data)
=/ b64-sig (en:base64:mimes:html (met 3 hmac-sig) (swp 3 hmac-sig))
=/ headers
:~ ['X-Twilio-Signature' b64-sig]
['Content-Type' 'application/x-www-form-urlencoded']
==
=/ form-data (build-form-data params)
=/ =request:http
[%'POST' url headers `[(met 3 form-data) form-data]]
[%pass wire %arvo %i %request request *outbound-config:iris]
::
++ build-form-data
|= data=(list [@t @t])
^- @t
%+ roll data
|= [[p=@t q=@t] out=@t]
?: =(out '')
(rap 3 p '=' q ~)
(rap 3 out '&' p '=' q ~)
::
++ send-notification
|= [entry=provider-entry who=@p =notification]
^- card
=/ params=(list [@t @t])
:~ identity+(rsh [3 1] (scot %p who))
ship+(rsh [3 1] (scot %p entity.resource.notification))
graph+name.resource.notification
:- %node
%+ roll index.notification
|= [in=@ out=@t]
(rap 3 out '/' (scot %ud in) ~)
==
%: post-form
/send-notification/(scot %uv (sham eny.bowl))
notify-endpoint.entry
auth-token.entry
params
==
::
++ register-binding
|= [service=term entry=provider-entry url=@t who=@p address=@t]
^- card
=/ params=(list [@t @t])
:~ identity+(rsh [3 1] (scot %p who))
bindingtype+'apn'
address+address
action+'add'
==
%: post-form
/register-binding/(scot %p who)/[service]/(scot %uv (sham eny.bowl))
binding-endpoint.entry
auth-token.entry
params
==
::
++ remove-binding
|= [service=term entry=provider-entry who=@p url=@t sid=@t]
^- card
=/ params=(list [@t @t])
:~ sid+sid
action+'remove'
==
%: post-form
/remove-binding/(scot %p who)/[service]/(scot %uv (sham eny.bowl))
binding-endpoint.entry
auth-token.entry
params
==
--

View File

@ -0,0 +1,11 @@
:: group-view|join: Join a group
::
/- view=group-view
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[him=ship name=term ~] ~]
==
::
:- %group-view-action
^- action:view
[%join [him name] him]

View File

@ -0,0 +1,20 @@
:: Kiln: Fuse local desk from (optionally-)foreign sources
::
:::: /hoon/fuse/hood/gen
::
/+ *hood-kiln
/* help-text %txt /gen/hood/fuse/help/txt
=, clay
::
::::
::
=>
|%
+$ fuse-list-arg $@(~ [des=desk ~])
--
:- %say
|= [* [arg=fuse-list-arg] ~]
:- %kiln-fuse-list
?~ arg
~
`des.arg

View File

@ -2,14 +2,59 @@
::
:::: /hoon/fuse/hood/gen
::
/+ *hood-kiln
/* help-text %txt /gen/hood/fuse/help/txt
=, clay
::
::::
::
=>
|%
+$ fuse-arg
$: des=desk
:: specified as [germ path] instead of [path germ] so
:: users can write mate//=home= instead of [/=home= %mate]
::
res=[?([%cancel ~] [bas=path con=(list [germ path])])]
==
::
++ parse-fuse-source
|= bec=beak
^- fuse-source
:: This is a slight overload of the label, but
:: it provides a nicer interface for the user so
:: we'll go with it.
::
?: ?=([%tas *] r.bec)
?: =(p.r.bec %track)
[p.bec q.bec %trak]
bec
bec
::
++ de-beak
|= pax=path
^- beak
=/ bem=beam (need (de-beam pax))
?> =(s.bem /)
-.bem
::
++ path-to-fuse-source
|= pax=path
^- fuse-source
(parse-fuse-source (de-beak pax))
--
:- %say
|= [[now=@da eny=@uvJ bec=beak] [arg=[?(~ [des=desk bas=beak con=(list [beak germ]) ~])]] ~]
|= [* [arg=[?(~ fuse-arg)]] [overwrite=$~(| flag) ~]]
:- %kiln-fuse
?~ arg
((slog (turn `wain`help-text |=(=@t leaf+(trip t)))) ~)
[des bas con]:arg
:- des.arg
?: ?=([%cancel ~] res.arg)
~
:+ overwrite
(path-to-fuse-source bas.res.arg)
%+ turn
con.res.arg
|= [g=germ pax=path]
^- [fuse-source germ]
[(path-to-fuse-source pax) g]

View File

@ -1,8 +1,21 @@
Usage:
|fuse %destination-desk base-beak ~[[source-beak %some-germ] [another-beak %another-germ]]
|fuse %dest /=kids= mate//~nel/home= meet//~zod/kids/track
|fuse %old-desk /=kids= only-that//~nus/test=, =overwrite &
|fuse %desk-to-cancel-fuse-into %cancel
A fuse replaces the contents of %destination-desk with the merge of the
specified beaks according to their merge strategies. This has no dependence
on the previous state of %destination-desk so any commits/work there will
be overwritten.
A %fuse request in clay replaces the contents of %destination-desk
with the merge of the specified beaks according to their merge
strategies. This has no dependence on the previous state of %dest
so any commits/work there will be overwritten.
|fuse extends this concept with the idea of a tracked source. When
specifying beaks to include in your fuse, specify %track instead of
a case. This will tell |fuse to retrieve the latest version of the
source beak AND to rerun the %fuse request whenever that tracked
source changes. A fuse can have many tracked sources, or none. The
base may be tracked as well.
The overwrite flag allows you to overwrite a currently ongoing fuse.
Without this flag, attempting a fuse into a desk that you already
|fuse'd into will error.

View File

@ -115,6 +115,16 @@
^- card
[%give %fact paths cage]
::
++ fact-all
|= =cage
^- (unit card)
=/ paths=(list path)
%+ turn ~(tap by sup.bowl)
|= [duct ship =path]
path
?~ paths ~
`[%give %fact paths cage]
::
++ kick
|= paths=(list path)
[%give %kick paths ~]

View File

@ -1,5 +1,6 @@
/- bc=bitcoin
/+ bcu=bitcoin-utils
~% %bip-158-top ..part ~
|%
++ params
|%
@ -8,6 +9,7 @@
--
::
++ siphash
~/ %siphash
|= [k=byts m=byts]
^- byts
|^
@ -86,25 +88,28 @@
:: write appends to the back
::
++ str
~% %str ..params ~
|%
++ read-bit
~/ %read-bit
|= s=bits:bc
^- [bit=@ub rest=bits:bc]
?> (gth wid.s 0)
:* ?:((gth wid.s (met 0 dat.s)) 0b0 0b1)
[(dec wid.s) (end [0 (dec wid.s)] dat.s)]
==
:+ ?:((gth wid.s (met 0 dat.s)) 0b0 0b1)
(dec wid.s)
(end [0 (dec wid.s)] dat.s)
::
::
++ read-bits
~/ %read-bits
|= [n=@ s=bits:bc]
^- [bits:bc rest=bits:bc]
=| bs=bits:bc
|-
?: =(n 0) [bs s]
=^ b s (read-bit s)
$(n (dec n), bs (write-bits bs [1 b]))
=/ r=@ (sub wid.s n)
:- n^(cut 0 [r n] dat.s)
r^(cut 0 [0 r] dat.s)
::
++ write-bits
~/ %write-bits
|= [s1=bits:bc s2=bits:bc]
^- bits:bc
[(add wid.s1 wid.s2) (can 0 ~[s2 s1])]
@ -112,6 +117,7 @@
:: +gol: Golomb-Rice encoding/decoding
::
++ gol
~% %gol ..params ~
|%
:: +en: encode x and append to end of s
:: - s: bits stream
@ -119,6 +125,7 @@
:: - p: golomb-rice p param
::
++ en
~/ %en
|= [s=bits:bc x=@ p=@]
^- bits:bc
=+ q=(rsh [0 p] x)
@ -128,6 +135,7 @@
(write-bits:str unary r)
::
++ de
~/ %de
|= [s=bits:bc p=@]
^- [delta=@ rest=bits:bc]
|^ ?> (gth wid.s 0)
@ -148,6 +156,7 @@
:: +hsh
::
++ hsh
~% %hsh ..params ~
|%
:: +to-range
:: - item: scriptpubkey to hash
@ -155,6 +164,7 @@
:: - k: key for siphash (end of blockhash, reversed)
::
++ to-range
~/ %to-range
|= [item=byts f=@ k=byts]
^- @
(rsh [0 64] (mul f (rev 3 (siphash k item))))
@ -171,6 +181,7 @@
--
::
++ parse-filter
~/ %parse-filter
|= filter=hexb:bc
^- [n=@ux gcs-set=bits:bc]
=/ n n:(de:csiz:bcu filter)
@ -180,6 +191,7 @@
:: +to-key: blockhash (little endian) to key for siphash
::
++ to-key
~/ %to-key
|= blockhash=tape
^- byts
%+ take:byt:bcu 16
@ -191,6 +203,7 @@
:: - targets: scriptpubkeys to match
::
++ match
~/ %match
|= [filter=hexb:bc k=byts targets=(list byts)]
^- ?
=/ [p=@ m=@] [p:params m:params]
@ -214,6 +227,7 @@
:: - targets: scriptpubkeys to match
::
++ all-match
~/ %all-match
|= [filter=hexb:bc blockhash=hexb:bc targets=(list [address:bc byts])]
^- (set [address:bc hexb:bc])
=/ k (to-key (trip (to-cord:hxb:bcu blockhash)))

View File

@ -110,6 +110,7 @@
%cancel-tx (hexb txid.upd)
%new-address (address address.upd)
%balance (balance balance.upd)
%scan-progress (scan-progress main.upd change.upd)
%error s+error.upd
%broadcast-success ~
==
@ -161,6 +162,19 @@
unconfirmed+(numb q.u.b)
==
::
++ scan-progress
|= [main=(unit idx:bitcoin) change=(unit idx:bitcoin)]
|^ ^- json
%- pairs
:~ main+(from-unit main)
change+(from-unit change)
==
++ from-unit
|= i=(unit idx:bitcoin)
?~ i ~
(numb u.i)
--
::
++ btc-state
|= bs=btc-state:btc-wallet
^- json

View File

@ -1,8 +1,8 @@
:: lib/bitcoin-utils.hoon
:: Utilities for working with BTC data types and transactions
::
/- sur=bitcoin
=, sur
/- *bitcoin
~% %bitcoin-utils-lib ..part ~
|%
::
:: TODO: move this bit/byt stuff to zuse
@ -12,6 +12,7 @@
:: +blop: munge bit and byt sequences (cat, flip, take, drop)
::
++ blop
~/ %blop
|_ =bloq
+$ biyts [wid=@ud dat=@]
++ cat
@ -48,6 +49,7 @@
++ byt ~(. blop 3)
::
++ bit
~/ %bit
=/ bl ~(. blop 0)
|%
++ cat cat:bl:bit
@ -79,16 +81,19 @@
:: big endian sha256: input and output are both MSB first (big endian)
::
++ sha256
~/ %sha256
|= =byts
^- hexb
%- flip:byt
[32 (shay (flip:byt byts))]
::
++ dsha256
~/ %dsha256
|= =byts
(sha256 (sha256 byts))
::
++ hash-160
~/ %hash-160
|= val=byts
^- hexb
=, ripemd:crypto
@ -100,8 +105,10 @@
:: hxb: hex parsing utilities
::
++ hxb
~% %hxb ..blop ~
|%
++ from-cord
~/ %from-cord
|= h=@t
^- hexb
?: =('' h) 1^0x0
@ -113,10 +120,11 @@
=+ (rsh [3 2] -)
:: Parse hex to atom
::
:- (div (lent (trip h)) 2)
`@ux`(rash - hex)
=/ a (need (de:base16:mimes:html -))
[-.a `@ux`+.a]
::
++ to-cord
~/ %to-cord
|= =hexb
^- cord
(en:base16:mimes:html hexb)
@ -128,8 +136,10 @@
:: - decode: little endian to big endian
::
++ csiz
~% %csiz ..blop ~
|%
++ en
~/ %en
|= a=@
^- hexb
=/ l=@ (met 3 a)
@ -140,6 +150,7 @@
~|("Cannot encode CompactSize longer than 8 bytes" !!)
::
++ de
~/ %de
|= h=hexb
^- [n=hexb rest=hexb]
=/ s=@ux dat:(take:byt 1 h)
@ -162,5 +173,4 @@
=> (de h)
[dat.n rest]
--
::
--

View File

@ -2,13 +2,13 @@
:: top-level Bitcoin constants
:: expose BIP libraries
::
/- sur=bitcoin
/- *bitcoin
/+ bech32=bip-b173, pbt=bip-b174, bcu=bitcoin-utils, bip-b158
=, sur
=, bcu
~% %bitcoin-lib ..part ~
|%
++ overhead-weight ^-(vbytes 11)
++ input-weight
~/ %input-weight
|= =bipt
^- vbytes
?- bipt
@ -40,8 +40,10 @@
:: adr: address manipulation
::
++ adr
~% %adr ..overhead-weight ~
|%
++ get-bipt
~/ %get-bipt
|= a=address
^- bipt
=/ spk=hexb (to-script-pubkey:adr a)
@ -52,35 +54,39 @@
~|("Invalid address" !!)
::
++ to-cord
~/ %to-cord
|= a=address ^- cord
?: ?=([%base58 *] a)
(scot %uc +.a)
%- crip
%+ slag 2
(scow %uc +.a)
+.a
::
++ from-pubkey
~/ %from-pubkey
|= [=bipt =network pubkey=hexb]
^- address
?- bipt
%44
:- %base58
=< ^-(@uc dat)
%- cat:byt
%- cat:byt:bcu
:- ?- network
%main 1^0x0
%testnet 1^0x6f
==
~[(hash-160 pubkey)]
~[(hash-160:bcu pubkey)]
::
%49
:- %base58
=< ^-(@uc dat)
%- cat:byt
%- cat:byt:bcu
:~ ?- network
%main 1^0x5
%testnet 1^0xc4
==
%- hash-160
(cat:byt ~[2^0x14 (hash-160 pubkey)])
%- hash-160:bcu
(cat:byt:bcu ~[2^0x14 (hash-160:bcu pubkey)])
==
::
%84
@ -89,6 +95,7 @@
==
::
++ from-cord
~/ %from-cord
|= addrc=@t
|^
=/ addrt=tape (trip addrc)
@ -117,12 +124,13 @@
--
::
++ to-script-pubkey
~/ %to-script-pubkey
|= =address
^- hexb
?- -.address
%bech32
=+ h=(from-address:bech32 +.address)
%- cat:byt
%- cat:byt:bcu
:~ 1^0x0
1^wid.h
h
@ -130,21 +138,21 @@
::
%base58
=/ h=hexb [21 `@ux`+.address]
=+ lead-byt=dat:(take:byt 1 h)
=+ lead-byt=dat:(take:byt:bcu 1 h)
=/ version-network=[bipt network]
?: =(0x0 lead-byt) [%44 %main]
?: =(0x6f lead-byt) [%44 %testnet]
?: =(0x5 lead-byt) [%49 %main]
?: =(0xc4 lead-byt) [%49 %testnet]
~|("Invalid base58 address: {<+.address>}" !!)
%- cat:byt
%- cat:byt:bcu
?: ?=(%44 -.version-network)
:~ 3^0x76.a914
(drop:byt 1 h)
(drop:byt:bcu 1 h)
2^0x88ac
==
:~ 2^0xa914
(drop:byt 1 h)
(drop:byt:bcu 1 h)
1^0x87
==
==
@ -155,6 +163,8 @@
:: - ignores signatures in inputs
::
++ txu
~% %bitcoin-lib-txu ..overhead-weight ~
=, bcu
|%
++ en
|%

View File

@ -1,8 +1,6 @@
/- bp=btc-provider, json-rpc
/+ bc=bitcoin
^?
::=< [sur .]
::=, sur
/+ bc=bitcoin, bcu=bitcoin-utils
~% %btc-provider-lib ..part ~
|%
:: +from-epoch: time since Jan 1, 1970 in seconds.
::
@ -25,8 +23,8 @@
~[['Content-Type' 'application/json']]
=, html
%- some
%- as-octt:mimes
(en-json body)
%- as-octt:mimes
(en-json body)
==
::
++ gen-request
@ -36,6 +34,7 @@
api-url.host-info ract
::
++ rpc
~/ %rpc
=, dejs:format
|%
++ parse-result
@ -62,6 +61,7 @@
%get-block-info
[id.res (block-info res.res)]
==
::
++ address-info
%- ot
:~ [%address (cu from-cord:adr:bc so)]
@ -69,47 +69,53 @@
[%used bo]
[%block ni]
==
::
++ utxo
%- ot
%- ot
:~ ['tx_pos' ni]
['tx_hash' (cu from-cord:hxb:bc so)]
['tx_hash' (cu from-cord:hxb:bcu so)]
[%height ni]
[%value ni]
[%recvd (cu from-epoch ni)]
==
::
++ tx-vals
%- ot
:~ [%included bo]
[%txid (cu from-cord:hxb:bc so)]
[%txid (cu from-cord:hxb:bcu so)]
[%confs ni]
[%recvd (cu from-epoch ni)]
[%inputs (ar tx-val)]
[%outputs (ar tx-val)]
==
::
++ tx-val
%- ot
:~ [%txid (cu from-cord:hxb:bc so)]
:~ [%txid (cu from-cord:hxb:bcu so)]
[%pos ni]
[%address (cu from-cord:adr:bc so)]
[%value ni]
==
::
++ raw-tx
%- ot
:~ [%txid (cu from-cord:hxb:bc so)]
[%rawtx (cu from-cord:hxb:bc so)]
:~ [%txid (cu from-cord:hxb:bcu so)]
[%rawtx (cu from-cord:hxb:bcu so)]
==
::
++ broadcast-tx
%- ot
:~ [%txid (cu from-cord:hxb:bc so)]
:~ [%txid (cu from-cord:hxb:bcu so)]
[%broadcast bo]
[%included bo]
==
::
++ block-info
%- ot
:~ [%block ni]
[%fee (mu ni)]
[%blockhash (cu from-cord:hxb:bc so)]
[%blockfilter (cu from-cord:hxb:bc so)]
[%blockhash (cu from-cord:hxb:bcu so)]
[%blockfilter (cu from-cord:hxb:bcu so)]
==
--
--
@ -126,17 +132,17 @@
%get-tx-vals
%- get-request
%+ mk-url '/gettxvals/'
(to-cord:hxb:bc txid.ract)
(to-cord:hxb:bcu txid.ract)
::
%get-raw-tx
%- get-request
%+ mk-url '/getrawtx/'
(to-cord:hxb:bc txid.ract)
(to-cord:hxb:bcu txid.ract)
::
%broadcast-tx
%- get-request
%+ mk-url '/broadcasttx/'
(to-cord:hxb:bc rawtx.ract)
(to-cord:hxb:bcu rawtx.ract)
::
%get-block-count
%- get-request

View File

@ -1,7 +1,7 @@
:: lib/btc.hoon
::
/- *btc-wallet, json-rpc, bp=btc-provider
/+ bip32, bc=bitcoin
/+ bip32, bc=bitcoin, bcu=bitcoin-utils
=, secp:crypto
=+ ecc=secp256k1
|%
@ -424,6 +424,7 @@
%get-block-info
[id.res (block-info res.res)]
==
::
++ address-info
%- ot
:~ [%address (cu from-cord:adr:bc so)]
@ -434,7 +435,7 @@
++ utxo
%- ot
:~ ['tx_pos' ni]
['tx_hash' (cu from-cord:hxb:bc so)]
['tx_hash' (cu from-cord:hxb:bcu so)]
[%height ni]
[%value ni]
[%recvd (cu from-epoch ni)]
@ -442,7 +443,7 @@
++ tx-vals
%- ot
:~ [%included bo]
[%txid (cu from-cord:hxb:bc so)]
[%txid (cu from-cord:hxb:bcu so)]
[%confs ni]
[%recvd (cu from-epoch ni)]
[%inputs (ar tx-val)]
@ -450,19 +451,19 @@
==
++ tx-val
%- ot
:~ [%txid (cu from-cord:hxb:bc so)]
:~ [%txid (cu from-cord:hxb:bcu so)]
[%pos ni]
[%address (cu from-cord:adr:bc so)]
[%value ni]
==
++ raw-tx
%- ot
:~ [%txid (cu from-cord:hxb:bc so)]
[%rawtx (cu from-cord:hxb:bc so)]
:~ [%txid (cu from-cord:hxb:bcu so)]
[%rawtx (cu from-cord:hxb:bcu so)]
==
++ broadcast-tx
%- ot
:~ [%txid (cu from-cord:hxb:bc so)]
:~ [%txid (cu from-cord:hxb:bcu so)]
[%broadcast bo]
[%included bo]
==
@ -470,8 +471,8 @@
%- ot
:~ [%block ni]
[%fee (mu ni)]
[%blockhash (cu from-cord:hxb:bc so)]
[%blockfilter (cu from-cord:hxb:bc so)]
[%blockhash (cu from-cord:hxb:bcu so)]
[%blockfilter (cu from-cord:hxb:bcu so)]
==
--
--
@ -488,17 +489,17 @@
%get-tx-vals
%- get-request
%+ mk-url '/gettxvals/'
(to-cord:hxb:bc txid.ract)
(to-cord:hxb:bcu txid.ract)
::
%get-raw-tx
%- get-request
%+ mk-url '/getrawtx/'
(to-cord:hxb:bc txid.ract)
(to-cord:hxb:bcu txid.ract)
::
%broadcast-tx
%- get-request
%+ mk-url '/broadcasttx/'
(to-cord:hxb:bc rawtx.ract)
(to-cord:hxb:bcu rawtx.ract)
::
%get-block-count
%- get-request

View File

@ -1,4 +1,4 @@
/- sur=graph-store, pos=post
/- sur=graph-store, pos=post, pull-hook
/+ res=resource, migrate
=< [sur .]
=< [pos .]
@ -872,6 +872,10 @@
^- card:agent:gall
=/ res-path (en-path:res rid)
=/ wire [%try-rejoin (scot %ud nack-count) res-path]
[%pass wire %agent [entity.rid %graph-push-hook] %watch resource+res-path]
=/ =cage
:- %pull-hook-action
!> ^- action:pull-hook
[%add [entity .]:rid]
[%pass wire %agent [our %graph-pull-hook] %poke cage]
--
--

View File

@ -96,22 +96,12 @@
?> ?=(%add-graph -.q.update)
graph.q.update
::
++ gut-younger-node-siblings
|= [res=resource =index:store]
^- (map index:store node:store)
=+ %+ scry-for ,=update:store
%+ weld
/node-siblings/younger/(scot %p entity.res)/[name.res]/all
(turn index (cury scot %ud))
?> ?=(%add-nodes -.q.update)
nodes.q.update
::
++ got-node
|= [res=resource =index:store]
^- node:store
=+ %+ scry-for ,=update:store
%+ weld
/node/(scot %p entity.res)/[name.res]
/graph/(scot %p entity.res)/[name.res]/node/index/kith
(turn index (cury scot %ud))
?> ?=(%add-nodes -.q.update)
?> ?=(^ nodes.q.update)
@ -122,7 +112,7 @@
^- ?
%+ scry-for ,?
%+ weld
/node-exists/(scot %p entity.res)/[name.res]
/graph/(scot %p entity.res)/[name.res]/node/exists
(turn index (cury scot %ud))
::
++ get-update-log
@ -134,13 +124,13 @@
++ peek-update-log
|= res=resource
^- (unit time)
(scry-for (unit time) /peek-update-log/(scot %p entity.res)/[name.res])
(scry-for (unit time) /update-log/(scot %p entity.res)/[name.res]/latest)
::
++ get-update-log-subset
|= [res=resource start=@da]
^- update-log:store
%+ scry-for update-log:store
/update-log-subset/(scot %p entity.res)/[name.res]/(scot %da start)/'~'
/update-log/(scot %p entity.res)/[name.res]/subset/'~'/(scot %da start)
::
++ get-keys
^- resources
@ -183,5 +173,5 @@
::
++ get-mark
|= res=resource
(scry-for ,(unit mark) /graph-mark/(scot %p entity.res)/[name.res])
(scry-for ,(unit mark) /graph/(scot %p entity.res)/[name.res]/mark)
--

View File

@ -145,6 +145,7 @@
%group-view
%settings-store
%dm-hook
%notify
==
::
++ deft-fish :: default connects
@ -341,6 +342,8 @@
(se-born | %home %group-view)
=? ..on-load (lte hood-version %13)
(se-born | %home %dm-hook)
=? ..on-load (lte hood-version %15)
(se-born | %home %notify)
..on-load
--
::

View File

@ -3,11 +3,29 @@
=, space:userlib
=, format
|%
+$ state [%1 pith-1]
+$ state state-2
+$ state-2 [%2 pith-2]
+$ state-1 [%1 pith-1]
+$ state-0 [%0 pith-0]
+$ any-state
$% state
[%0 pith-0]
$% state-2
state-1
state-0
==
+$ pith-2 ::
$: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) ::
ota=(unit [=ship =desk =aeon]) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request
:: and the latest version numbers for beaks to
fus=(map desk per-fuse)
:: used for fuses - every time we get a fuse we
:: bump this. used when calculating hashes to
:: ensure they're unique even when the same
:: request is made multiple times.
hxs=(map desk @ud)
== ::
+$ pith-1 ::
$: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) ::
@ -31,6 +49,15 @@
sud=@tas :: from desk
cas=case :: at case
==
+$ per-fuse :: per fuse state
:: map [ship desk] to latest version number we
:: have for them. used for things we're %trak-ing
:: our invariant here is to store the latest version
:: number we've heard of.
$: mox=(map [ship desk] let=@ud)
:: relevant parts of originating request
kf=kiln-fuse-data
==
+$ kiln-commit term ::
+$ kiln-mount ::
$: pax=path ::
@ -55,12 +82,26 @@
cas=case ::
gim=?(%auto germ) ::
==
+$ fuse-source [who=ship des=desk ver=$@(%trak case)]
:: actual poke
+$ kiln-fuse
$@ ~
$: syd=desk
bas=beak
con=(list [beak germ])
$@ ~ :: signifies clearing the fuse
$: overwrite=flag :: force overwrite previous fuse
bas=fuse-source
con=(list [fuse-source germ])
==
==
:: state tracked by kiln
+$ kiln-fuse-data
$: syd=desk
bas=fuse-source
con=(list [fuse-source germ])
==
:: Request to list current fuses. ~ means "list all"
::
+$ kiln-fuse-list (unit desk)
--
|= [bowl:gall state]
?> =(src our)
@ -85,6 +126,15 @@
~[leaf+"from {<sud>}" leaf+"on {<who>}" leaf+"to {<syd>}"]
::
++ on-load
=>
|%
++ state-1-to-2
|= s=state-1
^- state-2
=/ p=pith-1 +.s
:- %2
[rem.p syn.p ota.p commit-timer.p *(map desk per-fuse) *(map desk @ud)]
--
|= [hood-version=@ud old=any-state]
=< abet
=? . ?=(%0 -.old)
@ -97,8 +147,8 @@
?: &(=(%base syd.i.syncs) !=(our her.i.syncs) =(%kids sud.i.syncs))
`[syd her sud]:i.syncs
$(syncs t.syncs)
::
=. +<+.$.abet
%- state-1-to-2
=- old(- %1, |3 [ota=~ commit-timer.old], syn -)
?~ recognized-ota
syn
@ -108,7 +158,8 @@
(poke-internal:update `[her sud]:u.recognized-ota)
+(old +<+.$.abet)
::
?> ?=(%1 -.old)
=? old ?=(%1 -.old) (state-1-to-2 old)
?> ?=(%2 -.old)
=. +<+.$.abet old
..abet
::
@ -387,10 +438,76 @@
?~ +< abet
abet:abet:(merge:(work syd) ali sud cas gim)
::
++ poke-fuse-list
=>
|%
++ format-fuse
|= [into=desk pf=per-fuse]
^- tank
=/ sources=tape
%+ reel
con.kf.pf
|= [[fs=fuse-source g=germ] acc=tape]
^- tape
;: weld
" ["
(format-fuse-source fs)
" "
<g>
"]"
acc
==
:- %leaf
;: weld
"|fuse {<into>} "
(format-fuse-source bas.kf.pf)
sources
==
:: +format-fuse-source: fuse source -> beak -> path
::
++ format-fuse-source
|= fs=fuse-source
^- tape
=/ bec=beak [who.fs des.fs ?:(?=([%trak] ver.fs) [%tas %track] ver.fs)]
<(en-beam [bec /])>
--
|= k=kiln-fuse-list
^+ abet
%. abet
?~ k
?~ fus
(slog [leaf+"no ongoing fuses" ~])
%- slog
%+ roll
~(tap by `(map desk per-fuse)`fus)
|= [[syd=desk pf=per-fuse] acc=tang]
^- tang
[(format-fuse syd pf) acc]
=/ pfu=(unit per-fuse) (~(get by fus) u.k)
?~ pfu
(slog [leaf+"no ongoing fuse for {<u.k>}" ~])
(slog [(format-fuse u.k u.pfu) ~])
::
++ poke-fuse
|= k=kiln-fuse
?~ k abet
abet:(emit [%pass /kiln/fuse/[syd.k] %arvo %c [%fuse syd.k bas.k con.k]])
=/ payload +.k
?~ payload
:: cancelling an ongoing fuse
%- (slog [leaf+"cancelling fuse into {<syd.k>}" ~])
=/ f (fuzz syd.k now)
?~ f
abet
abet:abet:delete:u.f
?: &(!overwrite.payload (~(has by fus) syd.k))
((slog [leaf+"existing fuse into {<syd.k>} - need =overwrite &" ~]) abet)
=. fus (~(put by fus) syd.k [~ [syd.k bas.payload con.payload]])
=/ old-cnt=@ud (~(gut by hxs) syd.k 0)
=. hxs (~(put by hxs) syd.k +(old-cnt))
=/ f (fuzz syd.k now)
?~ f
abet
abet:abet:fuse:u.f
::
++ poke-cancel
|= a=@tas
@ -442,6 +559,7 @@
%kiln-label =;(f (f !<(_+<.f vase)) poke-label)
%kiln-merge =;(f (f !<(_+<.f vase)) poke-merge)
%kiln-fuse =;(f (f !<(_+<.f vase)) poke-fuse)
%kiln-fuse-list =;(f (f !<(_+<.f vase)) poke-fuse-list)
%kiln-mount =;(f (f !<(_+<.f vase)) poke-mount)
%kiln-ota =;(f (f !<(_+<.f vase)) poke:update)
%kiln-ota-info =;(f (f !<(_+<.f vase)) poke-ota-info)
@ -489,6 +607,21 @@
[%autocommit *] %+ take-wake-autocommit t.wire
?>(?=(%wake +<.sign-arvo) +>.sign-arvo)
[%ota *] abet:(take:update t.wire sign-arvo)
[%fuse-request @tas *]
=/ f (fuzz i.t.wire now)
?~ f
abet
abet:abet:(take:u.f t.t.wire sign-arvo)
[%fuse @tas *] ?> ?=(%mere +<.sign-arvo)
=/ syd=desk i.t.wire
?. ?=([%| *] +>.sign-arvo)
?~ p.p.sign-arvo
abet
=/ msg=tape "fuse merge conflict for {<syd>}"
%- (slog [leaf+msg >p.p.sign-arvo< ~])
abet
%- (slog leaf+"failed fuse for {<syd>}" p.p.sign-arvo)
abet
*
?+ +<.sign-arvo
((slog leaf+"kiln: strange card {<+<.sign-arvo wire>}" ~) abet)
@ -567,6 +700,122 @@
++ spam
|= mes=(list tank)
((slog mes) ..spam)
:: state machine for fuses
::
++ fuzz
|= [syd=desk now=@da]
=/ pfu=(unit per-fuse) (~(get by fus) syd)
?~ pfu
~
=* kf kf.u.pfu
=* mox mox.u.pfu
=/ should-delete=flag |
%- some
|%
:: finalize
::
++ abet
?: should-delete
..fuzz(fus (~(del by fus) syd))
..fuzz(fus (~(put by fus) syd [mox kf]))
::
++ delete
^+ ..delete
=. should-delete &
..delete
:: queue moves
::
++ blab
|= new=(list card:agent:gall)
^+ +>
+>.$(moz (welp new moz))
:: +make-requests: send requests for each %trak source.
::
++ make-requests
^+ ..abet
=/ movs=(list card:agent:gall)
%+ murn
[[bas.kf *germ] con.kf]
|= [fs=fuse-source germ]
^- (unit card:agent:gall)
?^ ver.fs
:: static source, don't need to track
~
=/ bec=beak (realize-fuse-source fs &)
?> =(who.fs p.bec)
?> =(des.fs q.bec)
=/ hax=@ud (mug [kf (~(got by hxs) syd)])
=/ wir=wire
/kiln/fuse-request/[syd]/(scot %p p.bec)/[q.bec]/(scot %ud hax)
=/ rav=rave [%sing %w r.bec /]
=/ rif=riff [q.bec `rav]
`[%pass wir %arvo %c [%warp who.fs rif]]
:: No need to keep state if all the sources are static
?~ movs
delete
(blab movs)
::
++ send-fuse
^+ ..abet
=/ bas=beak (realize-fuse-source bas.kf |)
=/ con=(list [beak germ])
%+ turn
con.kf
|= [fs=fuse-source g=germ]
[(realize-fuse-source fs |) g]
%- blab
[%pass /kiln/fuse/[syd] %arvo %c [%fuse syd bas con]]~
::
++ fuse
^+ ..abet
send-fuse:make-requests
::
++ take
|= [wir=wire =sign-arvo]
^+ ..fuse
?> =((lent wir) 3)
=/ who=ship (slav %p (snag 0 wir))
=/ src=desk (snag 1 wir)
=/ hax=@ud (slav %ud (snag 2 wir))
?. =(hax (mug [kf (~(got by hxs) syd)]))
:: If the hash in the wire doesn't match the current request
:: this is a response for a previous fuse that we can ignore.
..take
?> ?=([?(%clay %behn) %writ *] sign-arvo)
=/ gif +.sign-arvo
?~ p.gif
%- (slog leaf+"|fuse request failed for {<src>} on <who> - cancelling")
delete
=/ cas=cass:clay !<(cass:clay +.r.u.p.gif)
=. mox (~(put by mox) [who src] ud.cas)
fuse
::
:: utility functions below
::
:: +realize-fuse-source: convert a fuse-source to a
:: fully realized beak.
::
++ realize-fuse-source
|= [fs=fuse-source incr=flag]
^- beak
:+ who.fs
des.fs
?@ ver.fs
(realize-case [who.fs des.fs incr])
`case`ver.fs
::
++ realize-case
|= [who=ship des=desk incr=flag]
^- case
=/ let=(unit @ud) (~(get by mox) [who des])
^- case
?~ let
da+now
:- %ud
?: incr
+(u.let)
u.let
--
::
++ auto
|= kiln-sync

View File

@ -37,6 +37,17 @@
[%metadata (^metadatum metadatum)]
==
::
++ edit-field
|= edt=^edit-field
^- json
%+ frond -.edt
^- json
?- -.edt
%color [%s `@t`(scot %ux color.edt)]
?(%title %description %picture %vip) [%s `@t`+.edt]
?(%preview %hidden) [%b `?`+.edt]
==
::
++ metadatum
|= met=^metadatum
^- json
@ -85,6 +96,16 @@
[%resource s+(enjs-path:resource resource.resource.upd)]
[%metadata (metadatum metadatum.upd)]
==
::
%edit
:- %edit
%- pairs
:~ [%group s+(enjs-path:resource group.upd)]
[%app-name s+app-name.resource.upd]
[%resource s+(enjs-path:resource resource.resource.upd)]
[%edit (edit-field edit-field.upd)]
==
::
%updated-metadata
:- %add
%- pairs
@ -136,6 +157,25 @@
:~ [%add add]
[%remove remove]
[%initial-group initial-group]
[%edit edit]
==
::
++ edit
%- ot
:~ [%group dejs-path:resource]
[%resource md-resource]
[%edit edit-field]
==
::
++ edit-field
%- of
:~ [%title so]
[%description so]
[%color nu]
[%picture so]
[%preview bo]
[%hidden bo]
[%vip vip]
==
::
++ initial-group

View File

@ -30,7 +30,7 @@
|= =vase
^- (list resource)
=/ =update:store !<(update:store vase)
?. ?=(?(%add %remove %initial-group) -.update) ~
?. ?=(?(%add %remove %initial-group %edit) -.update) ~
~[group.update]
::
++ app-paths-from-group

View File

@ -514,7 +514,11 @@
^+ tr-core
?- -.action
%add (tr-add +.action)
%remove tr-remove:(tr-abed resource.action)
::
%remove
?. (~(has by tracking) resource.action)
tr-core
tr-remove:(tr-abed resource.action)
==
::
++ tr-cleanup

View File

@ -232,58 +232,76 @@
:: +veri:dawn: validate keys, life, discontinuity, &c
::
++ veri
|= [=seed:jael =point:azimuth =live]
^- (unit error=term)
=/ rac (clan:title who.seed)
=/ cub (nol:nu:crub:crypto key.seed)
?- rac
%pawn
:: a comet address is the fingerprint of the keypair
::
?. =(who.seed `@`fig:ex:cub)
`%key-mismatch
:: a comet can never be breached
::
?^ live
`%already-booted
:: a comet can never be re-keyed
::
?. ?=(%1 lyf.seed)
`%invalid-life
~
|= [=ship =feed:jael =point:azimuth =live]
^- (each seed:jael (lest error=term))
|^ ?@ -.feed
?^ err=(test feed) |+[u.err ~]
&+feed
?> ?=([%1 ~] -.feed)
=| errs=(list term)
|-
?~ kyz.feed
|+?~(errs [%no-key ~] errs)
=/ =seed:jael [who [lyf key ~]:i.kyz]:feed
?~ err=(test seed)
&+seed
=. errs (snoc errs u.err)
$(kyz.feed t.kyz.feed)
::
%earl
~
::
*
:: on-chain ships must be launched
++ test
|= =seed:jael
^- (unit error=term)
?. =(ship who.seed) `%not-our-key
=/ rac (clan:title who.seed)
=/ cub (nol:nu:crub:crypto key.seed)
?- rac
%pawn
:: a comet address is the fingerprint of the keypair
::
?. =(who.seed `@`fig:ex:cub)
`%key-mismatch
:: a comet can never be breached
::
?^ live
`%already-booted
:: a comet can never be re-keyed
::
?. ?=(%1 lyf.seed)
`%invalid-life
~
::
?~ net.point
`%not-keyed
=* net u.net.point
:: boot keys must match the contract
%earl
~
::
?. =(pub:ex:cub pass.net)
~& [%key-mismatch pub:ex:cub pass.net]
`%key-mismatch
:: life must match the contract
::
?. =(lyf.seed life.net)
`%life-mismatch
:: the boot life must be greater than and discontinuous with
:: the last seen life (per the sponsor)
::
?: ?& ?=(^ live)
?| ?=(%| breach.u.live)
(lte life.net life.u.live)
== ==
`%already-booted
:: produce the sponsor for vere
::
~? !has.sponsor.net
[%no-sponsorship-guarantees-from who.sponsor.net]
~
==
*
:: on-chain ships must be launched
::
?~ net.point
`%not-keyed
=* net u.net.point
:: boot keys must match the contract
::
?. =(pub:ex:cub pass.net)
`%key-mismatch
:: life must match the contract
::
?. =(lyf.seed life.net)
`%life-mismatch
:: the boot life must be greater than and discontinuous with
:: the last seen life (per the sponsor)
::
?: ?& ?=(^ live)
?| ?=(%| breach.u.live)
(lte life.net life.u.live)
== ==
`%already-booted
:: produce the sponsor for vere
::
~? !has.sponsor.net
[%no-sponsorship-guarantees-from who.sponsor.net]
~
==
--
:: +sponsor:dawn: retreive sponsor from point
::
++ sponsor

View File

@ -1,15 +1,22 @@
/+ store=metadata-store
|_ =update:store
|_ =update:one:store
++ grad %noun
++ grow
|%
++ noun update
++ json (update:enjs:store update)
++ metadata-update-2
^- update:store
update
--
::
++ grab
|%
++ noun update:store
++ json action:dejs:store
++ noun update:one:store
:: This is ok, we don't send %edit over the wire yet.
++ metadata-update-2
|= upd=update:store
^- update:one:store
?< ?=(%edit -.upd)
upd
--
--

View File

@ -0,0 +1,15 @@
/+ store=metadata-store
|_ =update:store
++ grad %noun
++ grow
|%
++ noun update
++ json (update:enjs:store update)
--
::
++ grab
|%
++ noun update:store
++ json action:dejs:store
--
--

View File

@ -0,0 +1,34 @@
/- *notify
|_ act=client-action
++ grad %noun
++ grow
|%
++ noun act
--
++ grab
|%
++ noun client-action
++ json
|= jon=^json
=, dejs:format
^- client-action
|^
%. jon
%- of
:~ connect-provider+connect-provider
remove-provider+remove-provider
==
++ connect-provider
%- ot
:~ who+(su fed:ag)
service+so
address+so
==
++ remove-provider
%- ot
:~ who+(su fed:ag)
service+so
==
--
--
--

View File

@ -0,0 +1,12 @@
/- *notify
|_ act=provider-action
++ grad %noun
++ grow
|%
++ noun act
--
++ grab
|%
++ noun provider-action
--
--

View File

@ -0,0 +1,12 @@
/- *notify
|_ upd=update
++ grad %noun
++ grow
|%
++ noun upd
--
++ grab
|%
++ noun update
--
--

View File

@ -24,6 +24,7 @@
$% [%set-credentials api-url=@t =network]
[%add-whitelist wt=whitelist-target]
[%remove-whitelist wt=whitelist-target]
[%set-interval inte=@dr]
==
+$ action
$% [%address-info =address]

View File

@ -162,6 +162,10 @@
[%new-address =address]
[%balance balance=(unit [confirmed=sats unconfirmed=sats])]
[%error =error]
:: current index being scanned in each wallet part
:: ~ if scan of that part is done
::
[%scan-progress main=(unit idx) change=(unit idx)]
==
::
--

View File

@ -44,6 +44,16 @@
[%empty ~]
==
::
+$ edit-field
$% [%title title=cord]
[%description description=cord]
[%color color=@ux]
[%picture =url]
[%preview preview=?]
[%hidden hidden=?]
[%vip vip=vip-metadata]
==
::
+$ metadatum
$: title=cord
description=cord
@ -60,6 +70,7 @@
+$ action
$% [%add group=resource resource=md-resource =metadatum]
[%remove group=resource resource=md-resource]
[%edit group=resource resource=md-resource =edit-field]
[%initial-group group=resource =associations]
==
::
@ -79,6 +90,18 @@
==
==
:: historical
++ one
|%
::
+$ action
$~ [%remove *resource *md-resource]
$< %edit ^action
::
+$ update
$~ [%remove *resource *md-resource]
$< %edit ^update
::
--
++ zero
|%
::

30
pkg/arvo/sur/notify.hoon Normal file
View File

@ -0,0 +1,30 @@
/- resource, graph-store
|%
+$ provider-action
$% [%add service=term notify=@t binding=@t auth-token=@t =whitelist]
[%remove service=term]
[%client-join service=term address=@t]
[%client-leave service=term]
==
::
+$ client-action
$% [%connect-provider who=@p service=term address=@t]
[%remove-provider who=@p service=term]
==
::
+$ notification
$: =resource:resource
=index:graph-store
==
::
+$ whitelist
$: public=?
kids=?
users=(set ship)
groups=(set resource:resource)
==
::
+$ update
$% [%notification =notification]
==
--

View File

@ -1865,7 +1865,12 @@
[%public-keys =public-keys-result] :: ethereum changes
[%turf turf=(list turf)] :: domains
== ::
:: +seed: private boot parameters
:: +feed: potential boot parameters
::
+$ feed
$^ [[%1 ~] who=ship kyz=(list [lyf=life key=ring])]
seed
:: +seed: individual boot parameters
::
+$ seed [who=ship lyf=life key=ring sig=(unit oath:pki)]
::

View File

@ -2099,7 +2099,7 @@
|= [k=beak v=(unit dome:clay)]
^- tank
=/ received=tape ?~(v "missing" "received")
leaf+"{<k>} {received}"
leaf+"{<(en-beam k ~)>} {received}"
:_ discarded
leaf+"fusing into {<syd>} from {<bas>} {<con>} - overwriting prior fuse"
=. fiz (make-melt bas con)
@ -2116,8 +2116,11 @@
:: responses we get for the merge will cause take-fuse to crash
::
=. fiz *melt
((slog [leaf+"clay: fuse failed, missing {<bec>}"]~) ..take-fuse)
?> (~(has by sto.fiz) bec)
=/ msg=tape <(en-beam bec ~)>
((slog [leaf+"clay: fuse failed, missing {msg}"]~) ..take-fuse)
?. (~(has by sto.fiz) bec)
=/ msg=tape <(en-beam bec ~)>
((slog [leaf+"clay: got strange fuse response {<msg>}"]~) ..take-fuse)
=. fiz
:+ bas.fiz con.fiz
(~(put by sto.fiz) bec `!<(dome:clay q.r.u.riot))
@ -2138,7 +2141,6 @@
|-
^+ ..take-fuse
?~ merges
=/ t=tang [leaf+"{<syd>} fused from {<bas.fiz>} {<con.fiz>}" ~]
=. ..take-fuse (done-fuse clean-state %& ~)
(park | [%| continuation-yaki(p (flop parents))] rag)
=/ [bec=beak g=germ] i.merges
@ -2146,7 +2148,8 @@
=/ result (merge-helper p.bec q.bec g ali-dom `continuation-yaki)
?- -.result
%|
(done-fuse clean-state %| %fuse-merge-failed p.result)
=/ failing-merge=tape "{<bec>} {<g>}"
(done-fuse clean-state %| %fuse-merge-failed leaf+failing-merge p.result)
::
%&
=/ merge-result=(unit merge-result) +.result

View File

@ -261,13 +261,18 @@
?- sih
[%gall %unto *]
:: ~& [%take-gall-unto +>.sih]
?- -.+>.sih
%poke-ack ?~(p.p.+>.sih +>.$ (crud %coup u.p.p.+>.sih))
%kick peer
%watch-ack ?~ p.p.+>.sih
+>.$
(dump:(crud %reap u.p.p.+>.sih) %logo ~)
%fact (from ;;(dill-blit q:`vase`+>+>.sih))
?- -.+>.sih
%poke-ack ?~(p.p.+>.sih +>.$ (crud %coup u.p.p.+>.sih))
%kick peer
%watch-ack
?~ p.p.+>.sih
+>.$
(dump:(crud %reap u.p.p.+>.sih) %logo ~)
::
%fact
?. ?=(%dill-blit p.cage.p.+>.sih)
+>.$
(from ;;(dill-blit q.q.cage.p.+>.sih))
==
::
[?(%behn %clay) %writ *]

View File

@ -554,6 +554,7 @@
:: +per-server-event: per-event server core
::
++ per-server-event
~% %eyre-per-server-event ..part ~
:: gate that produces the +per-server-event core from event information
::
|= [[eny=@ =duct now=@da rof=roof] state=server-state]
@ -781,7 +782,7 @@
:* duct %pass /run-app-request/[eyre-id]
%g %deal [our our] app
%poke %handle-http-request
!>([eyre-id inbound-request])
!>(`[@ta inbound-request:eyre]`[eyre-id inbound-request])
==
==
:: +cancel-request: handles a request being externally aborted
@ -1205,15 +1206,21 @@
?~ maybe-channel=(~(get by session.channel-state.state) channel-id)
%^ return-static-data-on-duct 404 'text/html'
(error-page 404 %.y url.request ~)
:: if there's already a duct listening to this channel, we must 400
::
?: ?=([%| *] state.u.maybe-channel)
%^ return-static-data-on-duct 400 'text/html'
(error-page 400 %.y url.request "channel already bound")
:: when opening an event-stream, we must cancel our timeout timer
:: if there's no duct already bound. Else, kill the old request
:: and replace it
::
=. moves
[(cancel-timeout-move channel-id p.state.u.maybe-channel) moves]
=^ cancel-moves state
?. ?=([%| *] state.u.maybe-channel)
:_ state
(cancel-timeout-move channel-id p.state.u.maybe-channel)^~
=/ cancel-heartbeat
?~ heartbeat.u.maybe-channel ~
:_ ~
%+ cancel-heartbeat-move channel-id
[date duct]:u.heartbeat.u.maybe-channel
=- [(weld cancel-heartbeat -<) ->]
(handle-response(duct p.state.u.maybe-channel) [%cancel ~])
:: the request may include a 'Last-Event-Id' header
::
=/ maybe-last-event-id=(unit @ud)
@ -1282,7 +1289,7 @@
|= =channel
channel(events ~, state [%| duct], heartbeat (some [heartbeat-time duct]))
::
[[heartbeat (weld http-moves moves)] state]
[[heartbeat :(weld http-moves cancel-moves moves)] state]
:: +acknowledge-events: removes events before :last-event-id on :channel-id
::
++ acknowledge-events
@ -1710,7 +1717,7 @@
=/ res
%- handle-response
:* %continue
data=(some (as-octs:mimes:html '\0a'))
data=(some (as-octs:mimes:html ':\0a'))
complete=%.n
==
=/ http-moves -.res

View File

@ -770,12 +770,10 @@
mo-core
=^ [=duct =routes blocker=(each deal sign:agent)] blocked
~(get to blocked)
?: ?=(%| -.blocker) $
=/ =move
=/ =sock [attributing.routes our]
=/ card
?: ?=(%& -.blocker)
[%slip %g %deal sock dap p.blocker]
[%pass /clear-huck %b %huck `sign-arvo`[%gall %unto p.blocker]]
=/ card [%slip %g %deal sock dap p.blocker]
[duct card]
$(moves [move moves])
:: +mo-filter-queue: remove all blocked tasks from ship.

View File

@ -431,7 +431,7 @@
%- curd =< abet
(private-keys:~(feel su hen now pki etn) life.tac ring.tac)
::
:: update private keys
:: register moon keys
::
%moon
?. =(%earl (clan:title ship.tac))
@ -710,6 +710,14 @@
=/ a-point=point (~(gut by pos.zim.pki) ship.i.udiffs *point)
=/ a-diff=(unit diff:point) (udiff-to-diff:point udiff.i.udiffs a-point)
=? this-su ?=(^ a-diff)
:: if this about our keys, and we already know these, start using them
::
=? lyf.own
?& =(our ship.i.udiffs)
?=(%keys -.u.a-diff)
(~(has by jaw.own) life.to.u.a-diff)
==
life.to.u.a-diff
(public-keys:feel original-pos %diff ship.i.udiffs u.a-diff)
$(udiffs t.udiffs)
::
@ -919,7 +927,16 @@
^+ ..feel
?: &(=(lyf.own life) =((~(get by jaw.own) life) `ring))
..feel
=. lyf.own life
:: only eagerly update lyf if we were behind the chain life
::
=? lyf.own
?& (gth life lyf.own)
::
=+ pon=(~(get by pos.zim) our)
?~ pon |
(lth lyf.own life.u.pon)
==
life
=. jaw.own (~(put by jaw.own) life ring)
(exec yen.own [%give %private-keys lyf.own jaw.own])
::

View File

@ -1,7 +1,7 @@
:: Note: these are for BTC testnet
::
/- spider, rpc=json-rpc
/+ strandio, bc=bitcoin
/+ strandio, bc=bitcoin, bcu=bitcoin-utils
=, strand=strand:spider
=>
|%
@ -47,8 +47,8 @@
++ electrs-script-hash
|= a=address:bc
^- hexb:bc
%- flip:byt:bc
%- sha256:bc
%- flip:byt:bcu
%- sha256:bcu
(to-script-pubkey:adr:bc a)
::
++ parse-json-rpc

View File

@ -46,7 +46,7 @@
(poke-our %graph-push-hook %push-hook-action !>([%add feed-rid]))
;< ~ bind:m
%+ poke-our %metadata-push-hook
:- %metadata-update-1
:- %metadata-update-2
!> ^- action:met
:^ %add
group.action
@ -54,7 +54,7 @@
metadatum(feed.config ``[%graph feed-rid])
;< ~ bind:m
%+ poke-our %metadata-push-hook
:- %metadata-update-1
:- %metadata-update-2
!> ^- action:met
:^ %add
group.action

View File

@ -78,7 +78,7 @@
=/ met-action=action:met
[%add group graph+rid.action metadatum]
;< ~ bind:m
(poke-our %metadata-push-hook metadata-update-1+!>(met-action))
(poke-our %metadata-push-hook metadata-update-2+!>(met-action))
::
:: Send invites
::

View File

@ -41,7 +41,7 @@
(poke-our %graph-push-hook %push-hook-action !>([%remove rid]))
;< ~ bind:m
%+ poke-our %metadata-push-hook
:- %metadata-update-1
:- %metadata-update-2
!> ^- action:metadata
[%remove group-rid [%graph rid]]
(pure:m ~)

View File

@ -31,7 +31,7 @@
==
;< ~ bind:m
%+ poke-our %metadata-push-hook
:- %metadata-update-1
:- %metadata-update-2
!> ^- action:met
:^ %add
group.action

View File

@ -4,42 +4,34 @@
|%
++ strand strand:spider
++ poke poke:strandio
++ poke-our poke-our:strandio
++ raw-poke-our raw-poke-our:strandio
::
++ scry-metadata
|= rid=resource
=/ m (strand ,resource)
^- form:m
;< group=(unit resource) bind:m
%+ scry:strandio ,(unit resource)
;: weld
/gx/metadata-store/resource/graph
(en-path:resource rid)
/noun
==
(pure:m (need group))
%+ scry:strandio ,(unit resource)
;: weld
/gx/metadata-store/resource/graph
(en-path:resource rid)
/noun
==
::
++ scry-group
|= rid=resource
=/ m (strand ,group)
^- form:m
;< ugroup=(unit group) bind:m
%+ scry:strandio ,(unit group)
;: weld
/gx/group-store/groups
(en-path:resource rid)
/noun
==
(pure:m (need ugroup))
%+ scry:strandio ,(unit group)
;: weld
/gx/group-store/groups
(en-path:resource rid)
/noun
==
::
++ delete-graph
|= [now=time rid=resource]
=/ m (strand ,~)
^- form:m
;< ~ bind:m
(poke-our %graph-pull-hook %pull-hook-action !>([%remove rid]))
(raw-poke-our %graph-pull-hook %pull-hook-action !>([%remove rid]))
;< ~ bind:m
(poke-our %graph-store %graph-update-2 !>([now [%remove-graph rid]]))
(raw-poke-our %graph-store %graph-update-2 !>([now [%remove-graph rid]]))
(pure:m ~)
--
::
@ -52,10 +44,12 @@
;< =bowl:spider bind:m get-bowl:strandio
?: =(our.bowl entity.rid.action)
(strand-fail:strandio %bad-request ~)
;< group-rid=resource bind:m (scry-metadata rid.action)
;< g=group bind:m (scry-group group-rid)
;< group-rid=(unit resource) bind:m (scry-metadata rid.action)
?~ group-rid (pure:m !>(~))
;< g=(unit group) bind:m (scry-group u.group-rid)
?~ g (pure:m !>(~))
;< ~ bind:m (delete-graph now.bowl rid.action)
?. hidden.g
?. hidden.u.g
(pure:m !>(~))
;< =thread-result:strandio bind:m
(await-thread:strandio %group-leave !>([~ [%leave rid.action]]))

View File

@ -41,6 +41,7 @@
date-created now.bowl
creator our.bowl
config [%group ~]
hidden %.n
==
=/ met-action=action:metadata
[%add rid groups+rid metadatum]

View File

@ -7,9 +7,9 @@
/+ strandio, resource, view=group-view
=>
|%
++ strand strand:spider
++ poke poke:strandio
++ poke-our poke-our:strandio
++ strand strand:spider
++ poke poke:strandio
++ raw-poke-our raw-poke-our:strandio
--
^- thread:spider
|= arg=vase
@ -22,9 +22,9 @@
:- %pull-hook-action
!> ^- action:pull-hook
[%remove rid]
;< ~ bind:m (poke-our %contact-pull-hook pull-hook-act)
;< ~ bind:m (poke-our %metadata-pull-hook pull-hook-act)
;< ~ bind:m (poke-our %group-pull-hook pull-hook-act)
;< ~ bind:m (poke-our %group-store %group-update-0 !>([%remove-group rid ~]))
;< ~ bind:m (raw-poke-our %contact-pull-hook pull-hook-act)
;< ~ bind:m (raw-poke-our %metadata-pull-hook pull-hook-act)
;< ~ bind:m (raw-poke-our %group-pull-hook pull-hook-act)
;< ~ bind:m (raw-poke-our %group-store %group-update-0 !>([%remove-group rid ~]))
;< ~ bind:m (cleanup-md:view rid)
(pure:m !>(~))

View File

@ -11,7 +11,7 @@
|= arg=vase
=/ m (strand ,vase)
^- form:m
=+ !<(desks=(list desk) arg)
=+ !<([~ desks=(list desk)] arg)
=? desks =(~ desks) [%work]~
|- ^- form:m
=* loop $

View File

@ -1,4 +1,4 @@
/+ *test, *bitcoin, bip32
/+ *test, *bitcoin, *bitcoin-utils, bip32
=, secp:crypto
=+ ecc=secp256k1
|%

View File

@ -188,37 +188,53 @@
++ test-veri-good
=/ sed [~zod 1 sec ~]
%+ expect-eq
!> ~
!> (veri:dawn sed pot ~)
!> &+sed
!> (veri:dawn ~zod sed pot ~)
::
++ test-veri-not-spawned
=/ sed [~zod 1 sec ~]
%+ expect-eq
!> `%not-keyed
!> (veri:dawn sed =>(pot .(net ~)) ~)
!> |+[%not-keyed ~]
!> (veri:dawn ~zod sed =>(pot .(net ~)) ~)
::
++ test-veri-wrong-key
=/ sed [~zod 1 sec:ex:(pit:nu:crub:crypto 24 %foo) ~]
%+ expect-eq
!> `%key-mismatch
!> (veri:dawn sed pot ~)
!> |+[%key-mismatch ~]
!> (veri:dawn ~zod sed pot ~)
::
++ test-veri-life-mismatch
=/ sed [~zod 2 sec ~]
%+ expect-eq
!> `%life-mismatch
!> (veri:dawn sed pot ~)
!> |+[%life-mismatch ~]
!> (veri:dawn ~zod sed pot ~)
::
++ test-veri-bad-multikey
=/ fed=feed:jael
:- [%1 ~]
:- ~zod
:~ [1 sec:ex:(pit:nu:crub:crypto 24 %foo)]
[2 sec]
==
%+ expect-eq
!> |+[%key-mismatch %life-mismatch ~]
!> (veri:dawn ~zod fed pot ~)
::
++ test-veri-none-multikey
%+ expect-eq
!> |+[%no-key ~]
!> (veri:dawn ~zod [[%1 ~] ~zod ~] pot ~)
::
++ test-veri-already-booted
=/ sed [~zod 1 sec ~]
;: weld
%+ expect-eq
!> `%already-booted
!> (veri:dawn sed pot `[1 |])
!> |+[%already-booted ~]
!> (veri:dawn ~zod sed pot `[1 |])
::
%+ expect-eq
!> `%already-booted
!> (veri:dawn sed pot `[2 &])
!> |+[%already-booted ~]
!> (veri:dawn ~zod sed pot `[2 &])
==
::
++ test-veri-earl-good
@ -230,8 +246,8 @@
(shaf %earl (sham who 1 pub:ex:cub))
[who 1 sec:ex:cub `sig]
%+ expect-eq
!> ~
!> (veri:dawn sed pot ~)
!> &+sed
!> (veri:dawn who sed pot ~)
::
++ test-veri-earl-parent-not-keyed
=/ cub (pit:nu:crub:crypto 24 %foo)
@ -242,38 +258,38 @@
(shaf %earl (sham who 1 pub:ex:cub))
[who 1 sec:ex:cub `sig]
%+ expect-eq
!> ~
!> (veri:dawn sed =>(pot .(net ~)) ~)
!> &+sed
!> (veri:dawn who sed =>(pot .(net ~)) ~)
::
++ test-veri-pawn-good
=/ cub (pit:nu:crub:crypto 24 %foo)
=/ who=ship `@`fig:ex:cub
=/ sed [who 1 sec:ex:cub ~]
%+ expect-eq
!> ~
!> (veri:dawn sed *point:azimuth-types ~)
!> &+sed
!> (veri:dawn who sed *point:azimuth-types ~)
::
++ test-veri-pawn-key-mismatch
=/ cub (pit:nu:crub:crypto 24 %foo)
=/ who=ship `@`fig:ex:cub
=/ sed [who 1 sec:ex:(pit:nu:crub:crypto 24 %bar) ~]
%+ expect-eq
!> `%key-mismatch
!> (veri:dawn sed *point:azimuth-types ~)
!> |+[%key-mismatch ~]
!> (veri:dawn who sed *point:azimuth-types ~)
::
++ test-veri-pawn-invalid-life
=/ cub (pit:nu:crub:crypto 24 %foo)
=/ who=ship `@`fig:ex:cub
=/ sed [who 2 sec:ex:cub ~]
%+ expect-eq
!> `%invalid-life
!> (veri:dawn sed *point:azimuth-types ~)
!> |+[%invalid-life ~]
!> (veri:dawn who sed *point:azimuth-types ~)
::
++ test-veri-pawn-already-booted
=/ cub (pit:nu:crub:crypto 24 %foo)
=/ who=ship `@`fig:ex:cub
=/ sed [who 1 sec:ex:cub ~]
%+ expect-eq
!> `%already-booted
!> (veri:dawn sed *point:azimuth-types `[1 |])
!> |+[%already-booted ~]
!> (veri:dawn who sed *point:azimuth-types `[1 |])
--

View File

@ -0,0 +1,27 @@
{
"env": {
"browser": true,
"es6": true
},
"extends": ["eslint:recommended", "plugin:react/recommended", "prettier"],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module"
},
"plugins": ["react"],
"rules": {
"react/prop-types": 0
},
"settings": {
"react": {
"version": "detect"
}
}
}

1
pkg/btc-wallet/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.eslintcache

1
pkg/btc-wallet/.husky/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
_

View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd pkg/btc-wallet && npx lint-staged src

View File

@ -0,0 +1,4 @@
{
"semi": true,
"singleQuote": true
}

View File

@ -5,4 +5,4 @@ dojo:
it should return with the following hash:
`0v1.9p61c.bd4vn.deevh.0ldbq.fkqo3`
`0v7.v4dng.o33qi.kc497.5jc02.ke5es`

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,8 @@
{
"name": "urbit-bitcoin-wallet",
"name": "btc-wallet",
"version": "0.1.0",
"main": "node install.js",
"private": true,
"scripts": {
"start": "webpack-dev-server --config config/webpack.dev.js",
"build:dev": "cross-env NODE_ENV=production webpack --config config/webpack.dev.js",
@ -24,8 +25,14 @@
"babel-plugin-root-import": "^6.5.0",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.2",
"eslint": "^7.29.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-react": "^7.24.0",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.2.0",
"husky": "^6.0.0",
"lint-staged": "^11.0.0",
"prettier": "^2.3.1",
"react-hot-loader": "^4.12.21",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
@ -71,5 +78,9 @@
},
"resolutions": {
"natives": "1.1.3"
},
"lint-staged": {
"*.js": "eslint --cache --fix",
"*.{js,css,md}": "prettier --write"
}
}

View File

@ -10,8 +10,6 @@ import './css/custom.css';
// rebuild x3
window.NETWORK = 'testnet'; // 'bitcoin'
const channel = new window.channel();
api.setChannel(window.ship, channel);

View File

@ -7,10 +7,13 @@ class UrbitApi {
this.bindPaths = [];
}
bind(path, method, ship = this.ship, appl = "btc-wallet", success, fail) {
bind(path, method, ship = this.ship, appl = 'btc-wallet', success, fail) {
this.bindPaths = _.uniq([...this.bindPaths, path]);
window.subscriptionId = this.channel.subscribe(ship, appl, path,
window.subscriptionId = this.channel.subscribe(
ship,
appl,
path,
(err) => {
fail(err);
},
@ -19,32 +22,38 @@ class UrbitApi {
data: event,
from: {
ship,
path
}
path,
},
});
},
(err) => {
fail(err);
});
}
);
}
btcWalletCommand(data) {
return this.action("btc-wallet", "btc-wallet-command", data);
return this.action('btc-wallet', 'btc-wallet-command', data);
}
settingsEvent(data) {
return this.action("settings-store", "settings-event", data);
return this.action('settings-store', 'settings-event', data);
}
action(appl, mark, data) {
return new Promise((resolve, reject) => {
this.channel.poke(ship, appl, mark, data,
this.channel.poke(
this.ship,
appl,
mark,
data,
(json) => {
resolve(json);
},
(err) => {
reject(err);
});
}
);
});
}
}

View File

@ -1,17 +1,9 @@
import React, { Component } from 'react';
import {
Box,
Icon,
Row,
Text,
Button,
Col,
} from '@tlon/indigo-react';
import Send from './send.js'
import CurrencyPicker from './currencyPicker.js'
import { currencyToSats, satsToCurrency } from '../../lib/util.js';
import { Row, Text, Button, Col } from '@tlon/indigo-react';
import Send from './send.js';
import CurrencyPicker from './currencyPicker.js';
import { satsToCurrency } from '../../lib/util.js';
import { store } from '../../store.js';
export default class Balance extends Component {
constructor(props) {
@ -21,7 +13,7 @@ export default class Balance extends Component {
sending: false,
copiedButton: false,
copiedString: false,
}
};
this.copyAddress = this.copyAddress.bind(this);
}
@ -29,110 +21,149 @@ export default class Balance extends Component {
copyAddress(arg) {
let address = this.props.state.address;
navigator.clipboard.writeText(address);
this.props.api.btcWalletCommand({'gen-new-address': null});
this.props.api.btcWalletCommand({ 'gen-new-address': null });
if (arg === 'button'){
this.setState({copiedButton: true});
setTimeout(() => { this.setState({copiedButton: false}); }, 2000);
if (arg === 'button') {
this.setState({ copiedButton: true });
setTimeout(() => {
this.setState({ copiedButton: false });
}, 2000);
} else if (arg === 'string') {
this.setState({copiedString: true});
setTimeout(() => { this.setState({copiedString: false}); }, 2000);
this.setState({ copiedString: true });
setTimeout(() => {
this.setState({ copiedString: false });
}, 2000);
}
}
render() {
const sats = (this.props.state.confirmedBalance || 0);
const sats = this.props.state.confirmedBalance || 0;
const unconfirmedSats = this.props.state.unconfirmedBalance;
const unconfirmedString = unconfirmedSats ? ` (${unconfirmedSats}) ` : '';
const denomination = this.props.state.denomination;
const value = satsToCurrency(sats, denomination, this.props.state.currencyRates);
const sendDisabled = (sats === 0);
const addressText = (this.props.state.address === null) ? '' :
this.props.state.address.slice(0, 6) + '...' +
this.props.state.address.slice(-6);
const value = satsToCurrency(
sats,
denomination,
this.props.state.currencyRates
);
const sendDisabled = sats === 0;
const addressText =
this.props.state.address === null
? ''
: this.props.state.address.slice(0, 6) +
'...' +
this.props.state.address.slice(-6);
const conversion = this.props.state.currencyRates[denomination].last;
return (
<>
{this.state.sending ?
<Send
state={this.props.state}
api={api}
psbt={this.props.state.psbt}
fee={this.props.state.fee}
currencyRates={this.props.state.currencyRates}
shipWallets={this.props.state.shipWallets}
value={value}
denomination={denomination}
sats={sats}
conversion={conversion}
network={this.props.network}
error={this.props.state.error}
stopSending={() => {
this.setState({sending: false});
store.handleEvent({data: {psbt: '', fee: 0, error: '', "broadcast-fail": null}});
}}
/> :
<Col
height="400px"
width='100%'
backgroundColor="white"
borderRadius="48px"
justifyContent="space-between"
mb={5}
p={5}
>
<Row justifyContent="space-between">
<Text color="orange" fontSize={1}>Balance</Text>
<Text color="lightGray" fontSize="14px" mono style={{cursor: "pointer"}}
onClick={() => {this.copyAddress('string')}}>
{this.state.copiedString ? "copied" : addressText}
</Text>
<CurrencyPicker
api={this.props.api}
denomination={denomination}
currencies={this.props.state.currencyRates}
/>
</Row>
<Col justifyContent="center" alignItems="center">
<Text fontSize="40px" color="orange" style={{whiteSpace: "nowrap"}} >
{value}
</Text>
<Text fontSize={1} color="orange">{`${sats}${unconfirmedString} sats`}</Text>
</Col>
<Row flexDirection="row-reverse">
<Button children="Send"
disabled={sendDisabled}
fontSize={1}
fontWeight="bold"
color={sendDisabled ? "lighterGray" : "white"}
backgroundColor={sendDisabled ? "veryLightGray" : "orange"}
style={{cursor: sendDisabled ? "default" : "pointer" }}
borderColor="none"
borderRadius="24px"
height="48px"
onClick={() => this.setState({sending: true})}
/>
<Button children={(this.state.copiedButton) ? "Address Copied!" : "Copy Address"}
mr={3}
disabled={this.state.copiedButton}
fontSize={1}
fontWeight="bold"
color={(this.state.copiedButton) ? "green" : "orange"}
backgroundColor={(this.state.copiedButton) ? "veryLightGreen" : "midOrange" }
style={{cursor: (this.state.copiedButton) ? "default" : "pointer"}}
borderColor="none"
borderRadius="24px"
height="48px"
onClick={() => {this.copyAddress('button')}}
/>
</Row>
{this.state.sending ? (
<Send
state={this.props.state}
api={this.props.api}
psbt={this.props.state.psbt}
fee={this.props.state.fee}
currencyRates={this.props.state.currencyRates}
shipWallets={this.props.state.shipWallets}
value={value}
denomination={denomination}
sats={sats}
conversion={conversion}
network={this.props.network}
error={this.props.state.error}
stopSending={() => {
this.setState({ sending: false });
store.handleEvent({
data: { psbt: '', fee: 0, error: '', 'broadcast-fail': null },
});
}}
/>
) : (
<Col
height="400px"
width="100%"
backgroundColor="white"
borderRadius="48px"
justifyContent="space-between"
mb={5}
p={5}
>
<Row justifyContent="space-between">
<Text color="orange" fontSize={1}>
Balance
</Text>
<Text
color="lightGray"
fontSize="14px"
mono
style={{ cursor: 'pointer' }}
onClick={() => {
this.copyAddress('string');
}}
>
{this.state.copiedString ? 'copied' : addressText}
</Text>
<CurrencyPicker
api={this.props.api}
denomination={denomination}
currencies={this.props.state.currencyRates}
/>
</Row>
<Col justifyContent="center" alignItems="center">
<Text
fontSize="40px"
color="orange"
style={{ whiteSpace: 'nowrap' }}
>
{value}
</Text>
<Text
fontSize={1}
color="orange"
>{`${sats}${unconfirmedString} sats`}</Text>
</Col>
<Row flexDirection="row-reverse">
<Button
disabled={sendDisabled}
fontSize={1}
fontWeight="bold"
color={sendDisabled ? 'lighterGray' : 'white'}
backgroundColor={sendDisabled ? 'veryLightGray' : 'orange'}
style={{ cursor: sendDisabled ? 'default' : 'pointer' }}
borderColor="none"
borderRadius="24px"
height="48px"
onClick={() => this.setState({ sending: true })}
>
Send
</Button>
<Button
mr={3}
disabled={this.state.copiedButton}
fontSize={1}
fontWeight="bold"
color={this.state.copiedButton ? 'green' : 'orange'}
backgroundColor={
this.state.copiedButton ? 'veryLightGreen' : 'midOrange'
}
style={{
cursor: this.state.copiedButton ? 'default' : 'pointer',
}}
borderColor="none"
borderRadius="24px"
height="48px"
onClick={() => {
this.copyAddress('button');
}}
>
{this.state.copiedButton ? 'Address Copied!' : 'Copy Address'}
</Button>
</Row>
</Col>
}
)}
</>
);
}

View File

@ -6,7 +6,6 @@ import {
StatelessTextInput,
Icon,
Row,
Input,
LoadingSpinner,
} from '@tlon/indigo-react';
@ -23,9 +22,9 @@ export default class ProviderModal extends Component {
ready: false,
provider: null,
connecting: false,
}
};
this.checkProvider = this.checkProvider.bind(this);
this.checkProvider = this.checkProvider.bind(this);
this.submitProvider = this.submitProvider.bind(this);
}
@ -38,77 +37,88 @@ export default class ProviderModal extends Component {
if (isValidPatp(provider)) {
let command = {
"check-provider": provider
}
'check-provider': provider,
};
potentialProvider = provider;
checkingProvider = true;
this.props.api.btcWalletCommand(command);
setTimeout(() => {
this.setState({providerFailed: true, checkingProvider: false});
this.setState({ providerFailed: true, checkingProvider: false });
}, 5000);
}
this.setState({provider, ready, checkingProvider, potentialProvider});
this.setState({ provider, ready, checkingProvider, potentialProvider });
}
componentDidUpdate(prevProps, prevState){
if (!this.state.ready){
componentDidUpdate() {
if (!this.state.ready) {
if (this.props.providerPerms[this.state.provider]) {
this.setState({ready: true, checkingProvider: false, providerFailed: false});
this.setState({
ready: true,
checkingProvider: false,
providerFailed: false,
});
}
}
}
submitProvider(e){
if (this.state.ready){
submitProvider() {
if (this.state.ready) {
let command = {
"set-provider": this.state.provider
}
'set-provider': this.state.provider,
};
this.props.api.btcWalletCommand(command);
this.setState({connecting: true});
this.setState({ connecting: true });
}
}
render() {
let workingNode = null;
let workingColor = null;
let workingBg = null;
if (this.state.ready) {
workingColor = "green";
workingBg = "veryLightGreen"
workingNode =
workingColor = 'green';
workingBg = 'veryLightGreen';
workingNode = (
<Box mt={3}>
<Text fontSize="14px" color="green">
{this.state.provider} is a working provider node
</Text>
</Box>
);
} else if (this.state.providerFailed) {
workingColor = "red";
workingBg = "veryLightRed"
workingNode =
workingColor = 'red';
workingBg = 'veryLightRed';
workingNode = (
<Box mt={3}>
<Text fontSize="14px" color="red">
{this.state.potentialProvider} is not a working provider node
</Text>
</Box>
);
}
return (
<Box
width="100%"
height="100%"
padding={3}
>
<Box width="100%" height="100%" padding={3}>
<Row>
<Icon icon="Bitcoin" mr={2}/>
<Icon icon="Bitcoin" mr={2} />
<Text fontSize="14px" fontWeight="bold">
Step 1 of 2: Set up Bitcoin Provider Node
</Text>
</Row>
<Box mt={3}>
<Text fontSize="14px" fontWeight="regular" color="gray">
In order to perform Bitcoin transaction in Landscape, you'll need to set a provider node. A provider node is an urbit which maintains a synced Bitcoin ledger.
<a fontSize="14px" target="_blank" href="https://urbit.org/bitcoin-wallet"> Learn More</a>
In order to perform Bitcoin transaction in Landscape, you&apos;ll
need to set a provider node. A provider node is an urbit which
maintains a synced Bitcoin ledger.
<a
fontSize="14px"
target="_blank"
href="https://urbit.org/bitcoin-wallet"
rel="noreferrer"
>
{' '}
Learn More
</a>
</Text>
</Box>
<Box mt={3} mb={2}>
@ -132,7 +142,7 @@ export default class ProviderModal extends Component {
borderColor={workingColor}
onChange={this.checkProvider}
/>
{(this.state.checkingProvider) ? <LoadingSpinner/> : null}
{this.state.checkingProvider ? <LoadingSpinner /> : null}
</Row>
{workingNode}
<Row alignItems="center" mt={3}>
@ -140,12 +150,15 @@ export default class ProviderModal extends Component {
mr={2}
primary
disabled={!this.state.ready}
children="Set Peer Node"
fontSize="14px"
style={{cursor: this.state.ready ? "pointer" : "default"}}
onClick={() => {this.submitProvider(this.state.provider)}}
/>
{(this.state.connecting) ? <LoadingSpinner/> : null}
style={{ cursor: this.state.ready ? 'pointer' : 'default' }}
onClick={() => {
this.submitProvider(this.state.provider);
}}
>
Set Peer Node
</Button>
{this.state.connecting ? <LoadingSpinner /> : null}
</Row>
</Box>
);

View File

@ -1,70 +1,71 @@
import React, { Component } from 'react';
import {
Box,
Icon,
Row,
Text,
Button,
Col,
LoadingSpinner,
} from '@tlon/indigo-react';
import { Sigil } from './sigil.js'
import { Box, Icon, Row, Text, LoadingSpinner } from '@tlon/indigo-react';
export default class TxAction extends Component {
constructor(props) {
super(props);
}
render() {
const leftIcon =
(this.props.action === "sent") ? "ArrowSouth" :
(this.props.action === "recv") ? "ArrowNorth" :
(this.props.action === "fail") ? "X" :
"NullIcon";
this.props.action === 'sent'
? 'ArrowSouth'
: this.props.action === 'recv'
? 'ArrowNorth'
: this.props.action === 'fail'
? 'X'
: 'NullIcon';
const actionColor =
(this.props.action === "sent") ? "sentBlue" :
(this.props.action === "recv") ? "recvGreen" :
(this.props.action === "fail") ? "gray" :
"red";
this.props.action === 'sent'
? 'sentBlue'
: this.props.action === 'recv'
? 'recvGreen'
: this.props.action === 'fail'
? 'gray'
: 'red';
const actionText =
(this.props.action === "sent" && !this.props.pending) ? "Sent BTC" :
(this.props.action === "sent" && this.props.pending) ? "Sending BTC" :
(this.props.action === "recv" && !this.props.pending) ? "Received BTC" :
(this.props.action === "recv" && this.props.pending) ? "Receiving BTC" :
(this.props.action === "fail") ? "Failed" :
"error";
this.props.action === 'sent' && !this.props.pending
? 'Sent BTC'
: this.props.action === 'sent' && this.props.pending
? 'Sending BTC'
: this.props.action === 'recv' && !this.props.pending
? 'Received BTC'
: this.props.action === 'recv' && this.props.pending
? 'Receiving BTC'
: this.props.action === 'fail'
? 'Failed'
: 'error';
const pending = (!this.props.pending) ? null :
<LoadingSpinner
background="midOrange"
foreground="orange"
/>
const pending = !this.props.pending ? null : (
<LoadingSpinner background="midOrange" foreground="orange" />
);
const url = (this.props.network === 'testnet')
? `http://blockstream.info/testnet/tx/${this.props.txid}`
: `http://blockstream.info/tx/${this.props.txid}`;
const url =
this.props.network === 'testnet'
? `http://blockstream.info/testnet/tx/${this.props.txid}`
: `http://blockstream.info/tx/${this.props.txid}`;
return (
<Row alignItems="center">
<Box backgroundColor={actionColor}
width="24px"
height="24px"
textAlign="center"
alignItems="center"
borderRadius="2px"
mr={2}
p={1}
<Box
backgroundColor={actionColor}
width="24px"
height="24px"
textAlign="center"
alignItems="center"
borderRadius="2px"
mr={2}
p={1}
>
<Icon icon={leftIcon} color="white"/>
<Icon icon={leftIcon} color="white" />
</Box>
<Text color={actionColor} fontSize="14px">{actionText}</Text>
<a href={url} target="_blank">
<Icon color={actionColor} icon="ArrowNorthEast" ml={1} mr={2}/>
<Text color={actionColor} fontSize="14px">
{actionText}
</Text>
<a href={url} target="_blank" rel="noreferrer">
<Icon color={actionColor} icon="ArrowNorthEast" ml={1} mr={2} />
</a>
{pending}
</Row>

View File

@ -1,28 +1,16 @@
import React, { Component } from 'react';
import { BrowserRouter, Route } from "react-router-dom";
import _ from 'lodash';
import { BrowserRouter } from 'react-router-dom';
import { api } from '../api.js';
import { store } from '../store.js';
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
import { ThemeProvider } from 'styled-components';
import light from './themes/light';
import dark from './themes/dark';
import {
Text,
Box,
Reset,
Col,
LoadingSpinner,
} from '@tlon/indigo-react';
// import dark from './themes/dark';
import { Box, Reset } from '@tlon/indigo-react';
import StartupModal from './lib/startupModal.js';
import Header from './lib/header.js'
import Balance from './lib/balance.js'
import Transactions from './lib/transactions.js'
import Warning from './lib/warning.js'
import Body from './lib/body.js'
import { subscription } from '../subscription.js'
import Body from './lib/body.js';
import { subscription } from '../subscription.js';
const network = "bitcoin";
const network = 'bitcoin';
export class Root extends Component {
constructor(props) {
@ -32,8 +20,8 @@ export class Root extends Component {
store.setStateHandler(this.setState.bind(this));
}
componentDidMount(){
this.props.channel.setOnChannelError((e) => {
componentDidMount() {
this.props.channel.setOnChannelError(() => {
subscription.start();
});
subscription.start();
@ -42,34 +30,38 @@ export class Root extends Component {
render() {
const loaded = this.state.loaded;
const warning = this.state.showWarning;
const blur = (!loaded) ? false :
!(this.state.wallet && this.state.provider);
const blur = !loaded ? false : !(this.state.wallet && this.state.provider);
return (
<BrowserRouter>
<ThemeProvider theme={light}>
<Reset/>
{ (loaded) ? <StartupModal api={api} state={this.state} network={network}/> : null }
<Box display="flex"
flexDirection='column'
position='absolute'
alignItems='center'
backgroundColor='lightOrange'
width='100%'
<Reset />
{loaded ? (
<StartupModal api={api} state={this.state} network={network} />
) : null}
<Box
display="flex"
flexDirection="column"
position="absolute"
alignItems="center"
backgroundColor="lightOrange"
width="100%"
minHeight={loaded ? '100%' : 'none'}
height={loaded ? 'none' : '100%'}
style={{filter: (blur ? 'blur(8px)' : 'none')}}
px={[0,4]}
pb={[0,4]}
style={{ filter: blur ? 'blur(8px)' : 'none' }}
px={[0, 4]}
pb={[0, 4]}
>
<Body loaded={loaded}
<Body
loaded={loaded}
state={this.state}
api={api} network={network}
api={api}
network={network}
warning={warning}
/>
</Box>
</ThemeProvider>
</BrowserRouter>
)
);
}
}

View File

@ -2,5 +2,11 @@ module.exports = {
extends: '@urbit',
env: {
'jest': true
},
rules: {
// Because we use styled system, and use
// the convention of each prop on a new line
// we probably shouldn't keep this on
'max-lines-per-function': ['off', {}]
}
};

View File

@ -51,7 +51,7 @@ export const decorators = [
color: '0x26.3e0f',
groups: [],
},
'~sampel-palnet': {
'~sampel-palnet': {
status: 'A test status',
'last-updated': 1616609090555,
avatar: null,
@ -60,7 +60,7 @@ export const decorators = [
nickname: 'You',
color: '0x26.3e0f',
groups: [],
}
},
},
});
@ -133,6 +133,47 @@ export const decorators = [
},
},
},
previews: {
'/ship/~bollug-worlus/urbit-index': {
group: '/ship/~bollug-worlus/urbit-index',
channels: {
'/ship/~darrux-landes/index-weekly': {
metadata: {
preview: false,
vip: '',
title: 'Index Weekly',
description: '',
creator: '~bollug-worlus',
picture: '',
hidden: false,
config: {
graph: 'publish',
},
'date-created': '~2020.4.6..21.53.30..dc68',
color: '0x0',
},
'app-name': 'graph',
resource: '/ship/~bollug-worlus/index-weekly',
group: '/ship/~bollug-worlus/urbit-index',
},
},
members: 1237,
metadata: {
preview: false,
vip: '',
title: 'Urbit Index',
description: '',
creator: '~bollug-worlus',
picture: '',
hidden: false,
config: {
group: null,
},
'date-created': '~2020.4.6..21.53.30..dc68',
color: '0x0',
},
},
},
});
useContactState.setState({

View File

@ -28,12 +28,13 @@ module.exports = {
```
Change the URL to your livenet ship (if making front-end changes) or keep it the
same (if [developing on a local development ship][local]). Then, from
'pkg/interface':
same (if [developing on a local development ship][local]). Then, from the root
of the repository
```
npm ci
npm run start
```bash
npm i
npm run bootstrap
cd pkg/interface && npm run start
```
The dev server will start at `http://localhost:9000`. Sign in as you would

View File

@ -3,6 +3,7 @@
"version": "1.0.0",
"description": "",
"main": "index.js",
"private": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@reach/disclosure": "^0.10.5",
@ -13,8 +14,8 @@
"@tlon/indigo-light": "^1.0.7",
"@tlon/indigo-react": "^1.2.23",
"@tlon/sigil-js": "^1.4.3",
"@urbit/api": "file:../npm/api",
"@urbit/http-api": "file:../npm/http-api",
"@urbit/api": "^1.1.1",
"@urbit/http-api": "^1.2.1",
"any-ascii": "^0.1.7",
"aws-sdk": "^2.830.0",
"big-integer": "^1.6.48",
@ -83,7 +84,7 @@
"@types/yup": "^0.29.11",
"@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.24.0",
"@urbit/eslint-config": "file:../npm/eslint-config",
"@urbit/eslint-config": "^1.0.0",
"@welldone-software/why-did-you-render": "^6.1.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
@ -117,15 +118,15 @@
"lint-file": "eslint",
"tsc": "tsc",
"tsc:watch": "tsc --watch",
"preinstall": "./preinstall.sh",
"build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
"build:prod": "cd ../npm/api && npm ci && cd ../../interface && cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
"build:prod": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
"start": "webpack-dev-server --config config/webpack.dev.js",
"test": "jest",
"prepare": "cd ../.. && husky install pkg/interface/.husky",
"test": "tsc && jest",
"jest": "jest",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"chromatic": "chromatic --exit-zero-on-changes"
"chromatic": "chromatic --exit-zero-on-changes",
"hook-lint": "eslint --cache --fix"
},
"author": "",
"license": "MIT",

View File

@ -8,16 +8,17 @@ import useInviteState from '../state/invite';
import useLaunchState from '../state/launch';
import useSettingsState from '../state/settings';
import useLocalState from '../state/local';
import useStorageState from '../state/storage';
export async function bootstrapApi() {
airlock.onError = (e) => {
(async () => {
const { reconnect } = useLocalState.getState();
try {
useLocalState.setState({ subscription: 'reconnecting' });
await reconnect();
} catch (e) {
useLocalState.setState({ subscription: 'disconnected' });
console.log(e);
console.log('onError');
}
})();
};
@ -38,7 +39,8 @@ export async function bootstrapApi() {
useSettingsState,
useLaunchState,
useInviteState,
useGraphState
useGraphState,
useStorageState
].map(state => state.getState().initialize(airlock));
await Promise.all(promises);
}

View File

@ -10,8 +10,18 @@ const makeIndexes = () => new Map([
['other', []]
]);
export interface OmniboxItem {
title: string;
link: string;
app: string;
host: string;
description: string;
shiftLink: string;
shiftDescription: string;
}
// result schematic
const result = function(title, link, app, host, description = 'Open', shiftLink = null, shiftDescription = null) {
const result = function(title: string, link: string, app: string, host: string, description = 'Open', shiftLink = null as string | null, shiftDescription = null as string | null): OmniboxItem {
return {
'title': title,
'link': link,
@ -93,7 +103,7 @@ const otherIndex = function(config) {
return other;
};
export default function index(contacts, associations, apps, currentGroup, groups, hide) {
export default function index(contacts, associations, apps, currentGroup, groups, hide): Map<string, OmniboxItem[]> {
const indexes = makeIndexes();
indexes.set('ships', shipIndex(contacts));
// all metadata from all apps is indexed
@ -117,7 +127,7 @@ export default function index(contacts, associations, apps, currentGroup, groups
let app = each['app-name'];
if (each['app-name'] === 'contacts') {
app = 'groups';
};
}
if (each['app-name'] === 'graph') {
app = each.metadata.config.graph;
@ -159,4 +169,4 @@ export default function index(contacts, associations, apps, currentGroup, groups
indexes.set('other', otherIndex(hide));
return indexes;
};
}

View File

@ -0,0 +1,38 @@
export type SuspendState = 'result' | 'error' | 'pending';
export interface Suspender<T> {
read: () => T;
}
export function suspend<T>(awaiting: Promise<T>): Suspender<T> {
let state: SuspendState = 'pending';
let result: T | null = null;
const promise = awaiting
.then((res) => {
state = 'result';
result = res;
})
.catch((e) => {
state = 'error';
result = e;
});
return {
read: () => {
if (state === 'result') {
return result!;
} else if (state === 'error') {
throw result;
} else {
throw promise;
}
}
};
}
export function suspendWithResult<T>(result: T): Suspender<T> {
return {
read: () => result
};
}

View File

@ -5,7 +5,7 @@ const URL_REGEX = new RegExp(String(/^([^[\]]*?)(([\w\-\+]+:\/\/)[-a-zA-Z0-9:@;?
const PATP_REGEX = /^([\s\S]*?)(~[a-z_-]+)([\s\S]*)/;
const GROUP_REGEX = new RegExp(String(/^([\s\S ]*?)(~[-a-z_]+\/[-a-z]+)([\s\S]*)/.source));
const GROUP_REGEX = new RegExp(String(/^([\s\S ]*?)(~[-a-z_]+\/[-a-z0-9]+)([\s\S]*)/.source));
const convertToGroupRef = group => `web+urbitgraph://group/${group}`;
@ -33,9 +33,10 @@ const raceRegexes = (str) => {
content = { url: link[2] };
}
}
if(groupRef && groupRef[1].length < pfix?.length) {
const perma = parsePermalink(convertToGroupRef(groupRef?.[2]));
const [,,host] = perma?.group.split('/') ?? [];
if(groupRef && groupRef[1].length < pfix?.length && Boolean(perma) && urbitOb.isValidPatp(host)) {
pfix = groupRef[1];
const perma = parsePermalink(convertToGroupRef(groupRef[2]));
content = permalinkToReference(perma);
sfix = groupRef[3];
}

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