Compare commits

...

138 Commits
v0.7.1 ... main

Author SHA1 Message Date
Tony Garnock-Jones 3fb8028bab Bump version 2024-05-24 09:36:13 +02:00
Tony Garnock-Jones 3a4919b7f8 Handle Packet::Nop 2024-05-19 21:55:43 +02:00
Tony Garnock-Jones 3936abe3fb Merge latest changes from the syndicate-protocols repository 2024-05-19 21:55:01 +02:00
Tony Garnock-Jones 599b4ed469 Packet::Nop 2024-05-19 21:32:44 +02:00
Tony Garnock-Jones b9e0bf0520 Use python3 explicitly in .envrc 2024-05-06 12:29:36 +02:00
Tony Garnock-Jones 6e555c9fd5 Update binary schemas 2024-04-19 12:57:14 +02:00
Emery Hemingway 8ebde104ca http: order absent fields first
This makes the absent variants the default initialization for
some implementations.
2024-04-19 10:51:40 +02:00
Tony Garnock-Jones 05fd3ca22e Bump version 2024-04-10 17:10:34 +02:00
Tony Garnock-Jones 7df9ce5248 Merge latest changes from the syndicate-protocols repository 2024-04-10 17:09:56 +02:00
Tony Garnock-Jones c0239cf322 And with that we are almost back where we started with http.prs! 2024-04-10 15:16:35 +02:00
Tony Garnock-Jones 9cc4175f24 Cope with HTTP/1.0's optional Host header 2024-04-10 14:54:19 +02:00
Tony Garnock-Jones 70f42dd931 Another revision of http.prs 2024-04-10 14:31:27 +02:00
Tony Garnock-Jones ef1ebe6412 Sigh. <done> turns out to be a good idea in addition to <processing> 2024-04-10 13:24:25 +02:00
Tony Garnock-Jones d9e1be2e98 Update for new dataspace pattern language 2024-04-09 15:06:08 +02:00
Tony Garnock-Jones 6de5e96aa1 Merge latest changes from the syndicate-protocols repository 2024-04-09 14:27:45 +02:00
Tony Garnock-Jones ca18ca08df Alternative representation of dataspacePatterns 2024-04-09 09:15:21 +02:00
Tony Garnock-Jones 40ca168eac Repair typo 2024-04-09 09:13:51 +02:00
Tony Garnock-Jones 5a73e8d4c3 Alter dataspacePatterns language to make rec and arr more like dict 2024-04-04 16:31:09 +02:00
Tony Garnock-Jones 710ff91a64 Revise http protocol 2024-04-01 15:56:07 +02:00
Tony Garnock-Jones 6e5f626ac1 Bump version 2024-03-30 09:10:10 +01:00
Tony Garnock-Jones 92027e94a9 Repair missed case of catching CancelledError 2024-03-30 09:09:56 +01:00
Tony Garnock-Jones 420868eae7 Bump version 2024-03-30 09:07:27 +01:00
Tony Garnock-Jones 3035b43941 Mirror linked task behaviour from other implementations: default to terminating facet on task end, and also terminate facet on task exception 2024-03-30 09:07:09 +01:00
Tony Garnock-Jones 08e49fd14e Ignore CancelledError from actor system tasks 2024-03-30 09:06:32 +01:00
Tony Garnock-Jones a4c0bf3e6f Default `debug` to `None` to attempt to allow propagation of default debug settings 2024-03-30 09:05:41 +01:00
Tony Garnock-Jones e5b65ad0ed Use built-in asyncio main loop entry point for improved interrupt handling etc 2024-03-30 09:05:11 +01:00
Tony Garnock-Jones 42cb62c094 Bump version 2024-03-29 14:09:14 +01:00
Tony Garnock-Jones 561aa01fea Support connection_timeout 2024-03-29 14:08:24 +01:00
Tony Garnock-Jones 0429e59ad1 Repair incorrect log variable reference 2024-03-29 14:02:17 +01:00
Tony Garnock-Jones f2b8b433cc Allow direct use of the gatekeeper object (or whatever is actually directly exposed) 2024-03-29 14:01:27 +01:00
Tony Garnock-Jones 6f6993ce4c Print linked task tracebacks even when not run in an executor 2024-03-29 14:00:58 +01:00
Tony Garnock-Jones 0364c38068 Patch version 2024-03-29 13:19:24 +01:00
Tony Garnock-Jones 219188d34f Repair packaging to include package-data schema files 2024-03-29 13:18:49 +01:00
Tony Garnock-Jones d8af496d4e Remove websockets from mandatory dependencies 2024-03-29 12:44:47 +01:00
Tony Garnock-Jones f73d59b526 Move import websockets to WebsocketTunnelRelay 2024-03-29 12:41:10 +01:00
Tony Garnock-Jones e0b6838166 Update README 2024-03-29 12:40:36 +01:00
Tony Garnock-Jones 71c57f4ab7 Support script for retrieving package version 2024-03-29 12:32:48 +01:00
Tony Garnock-Jones c59e044695 Set embeddedType for noise 2024-03-28 15:49:48 +01:00
Tony Garnock-Jones bf0d47f1b7 Repair noise protocol 2024-03-28 15:17:28 +01:00
Tony Garnock-Jones 7797a3cd09 Updated description of gatekeeper protocol 2024-03-22 10:11:57 +01:00
Tony Garnock-Jones 1b72f71a32 Switch to pyproject.toml; bump to 0.16.0 for latest Preserves and protocols 2024-03-01 17:00:54 +01:00
Tony Garnock-Jones 956a84cc17 Update for preserves changes 2024-02-08 12:11:11 +01:00
Tony Garnock-Jones d457867cc5 Merge latest changes from the syndicate-protocols repository 2024-02-08 11:53:56 +01:00
Tony Garnock-Jones 9864ce0ec8 Switch `#!` to `#:` 2024-02-05 23:14:19 +01:00
Tony Garnock-Jones 5dd68e87c1 Preserves 0.993 lacks float 2024-02-03 15:16:23 +01:00
Tony Garnock-Jones 79c3788436 Avoid double-execution within a round; see syndicate-lang/syndicate-js#3 2023-12-19 23:15:00 +13:00
Tony Garnock-Jones 3b4d0ef418 Merge latest changes from the syndicate-protocols repository 2023-12-19 21:52:52 +13:00
Tony Garnock-Jones 97876335ba Save a few bytes on the wire. If not now, never I guess 2023-12-19 21:37:41 +13:00
Tony Garnock-Jones d7b330e6dd stdenv.prs 2023-12-04 22:25:40 +01:00
Tony Garnock-Jones b32dc0a947 Example config for inf.py 2023-11-10 17:04:45 +01:00
Tony Garnock-Jones 6d18f7549c Repair cancellation-overtaking-normal-termination issue with turn.external 2023-11-10 16:49:22 +01:00
Tony Garnock-Jones 796b1ac344 Version 0.15.0 for new Preserves 0.991 2023-10-31 22:44:53 +01:00
Tony Garnock-Jones bdb2d86622 Merge latest changes from the syndicate-protocols repository 2023-10-31 22:44:24 +01:00
Tony Garnock-Jones c0f83a2463 Update for new Preserves 2023-10-31 22:42:52 +01:00
Tony Garnock-Jones fe9ceaf65c Update comment syntax for Preserves 0.991 2023-10-31 21:56:44 +01:00
Tony Garnock-Jones 8bcfed2d4a Bump version 2023-10-18 14:06:01 +02:00
Tony Garnock-Jones ae2a9b59e6 Merge latest changes from the syndicate-protocols repository 2023-10-18 14:05:11 +02:00
Tony Garnock-Jones 72566ac223 Update for Preserves 0.990 2023-10-18 14:02:28 +02:00
Tony Garnock-Jones 23c622f914 Bump version 2023-03-06 23:25:08 +01:00
Tony Garnock-Jones bd71008e13 Executors; repair relay.service 2023-03-06 23:24:36 +01:00
Tony Garnock-Jones f00d75b74b chat.server-config.pr 2023-03-06 23:24:10 +01:00
Tony Garnock-Jones 17f9833708 Introduce actor System to keep track of outstanding tasks 2023-02-12 22:02:08 +01:00
Tony Garnock-Jones b957490d78 Bump 2023-02-11 21:50:26 +01:00
Tony Garnock-Jones 2b2d033efb Merge latest changes from the syndicate-protocols repository 2023-02-11 21:49:59 +01:00
Tony Garnock-Jones d8a139b23a Switch back to transport sequence representation 2023-02-11 21:49:49 +01:00
Tony Garnock-Jones b18dbf014c Grr 2023-02-11 17:44:14 +01:00
Tony Garnock-Jones 96997e86ac Merge latest changes from the syndicate-protocols repository 2023-02-11 17:43:58 +01:00
Tony Garnock-Jones 46fd2dec3b Set of any for transports in gatekeeper.Route 2023-02-11 17:43:42 +01:00
Tony Garnock-Jones c630d35ea9 Bump version 2023-02-11 17:34:13 +01:00
Tony Garnock-Jones ae2698557c tag target 2023-02-10 16:46:46 +01:00
Tony Garnock-Jones 587fba6887 Bump version 2023-02-10 16:45:29 +01:00
Tony Garnock-Jones ab85a1f078 New gatekeeper protocol 2023-02-10 12:16:23 +01:00
Tony Garnock-Jones 4e2db5b17b Merge latest changes from the syndicate-protocols repository 2023-02-10 12:06:37 +01:00
Tony Garnock-Jones 1ae2583414 Remove accidental self-qualification 2023-02-09 23:07:43 +01:00
Tony Garnock-Jones f3c9662607 Another small error 2023-02-08 23:43:51 +01:00
Tony Garnock-Jones 82624d3007 Another small error 2023-02-08 23:39:42 +01:00
Tony Garnock-Jones 8b690b9103 Repair minor error 2023-02-08 23:36:21 +01:00
Tony Garnock-Jones 5a52f243e5 Adjust steps in noise and sturdy 2023-02-08 23:11:05 +01:00
Tony Garnock-Jones 6224baa2b6 Avoid variable-arity steps 2023-02-08 23:04:42 +01:00
Tony Garnock-Jones 8619342e5e Refinements 2023-02-08 22:11:45 +01:00
Tony Garnock-Jones 5bcb268ff8 Adjust ResolvePath/TransportConnection/PathStep 2023-02-08 20:36:14 +01:00
Tony Garnock-Jones 6aba0ebe41 PROTOCOLS_BRANCH 2023-02-08 19:39:30 +01:00
Tony Garnock-Jones 9cd2e6776c Refactor gatekeeper protocols. 2023-02-08 17:46:47 +01:00
Tony Garnock-Jones a086c1d721 Repair typo 2023-02-07 13:18:18 +01:00
Tony Garnock-Jones bc41182533 Another small repair 2023-02-07 13:11:14 +01:00
Tony Garnock-Jones 2ad99b56b8 Be more precise about HMAC-BLAKE2s-256 and the key length 2023-02-07 12:44:47 +01:00
Tony Garnock-Jones 3fdf92daeb Version 0.9.0 2023-02-06 23:31:38 +01:00
Tony Garnock-Jones 2be479b1e9 Switch to HMAC-BLAKE2s 2023-02-06 17:35:44 +01:00
Tony Garnock-Jones 4684353018 Merge latest changes from the syndicate-protocols repository 2023-02-06 17:35:12 +01:00
Tony Garnock-Jones f6b88ee3fb Switch to HMAC-BLAKE2s 2023-02-06 16:19:03 +01:00
Tony Garnock-Jones ee8a23aa2e Switch from milliseconds to seconds. Fixes #1 2023-02-06 15:36:17 +01:00
Tony Garnock-Jones 6d4833d67e Merge latest changes from the syndicate-protocols repository 2023-02-06 15:23:39 +01:00
Tony Garnock-Jones 5cd0335a79 Argh, previous commit won't work 2023-02-06 11:06:02 +01:00
Tony Garnock-Jones b52da09081 More usable (?) rewrite language 2023-02-06 10:58:16 +01:00
Tony Garnock-Jones 9ca618268e Simplify attenuations 2023-02-06 10:45:41 +01:00
Tony Garnock-Jones 41dbeb1aae Merge latest changes from the syndicate-protocols repository 2023-02-04 16:31:22 +01:00
Tony Garnock-Jones 9f1f76d0ca Remove racketEvent.prs 2023-02-04 16:30:27 +01:00
Tony Garnock-Jones e0deaf3054 Standalone chat protocol 2023-02-04 16:27:31 +01:00
Tony Garnock-Jones 837570844d Merge latest changes from the syndicate-protocols repository 2023-02-04 16:09:34 +01:00
Tony Garnock-Jones f4078aabaa Update binary bundle 2023-02-04 13:46:49 +01:00
Tony Garnock-Jones 557a36756f First step of cleanup of protocols 2023-02-04 13:46:34 +01:00
Tony Garnock-Jones 07a5f688be Repair binary bundle 2023-01-27 12:52:07 +01:00
Tony Garnock-Jones fff84d4c2a Update noise mapping 2023-01-27 12:45:02 +01:00
Tony Garnock-Jones 5983cd01f1 Another note re noise 2023-01-23 13:08:12 +01:00
Tony Garnock-Jones e8881f5980 Now I have actually implemented Noise, revise the schema 2023-01-19 12:18:58 +01:00
Tony Garnock-Jones 40b4681a6e Ugh, xsalsa20poly1305 as an AEAD isn't a thing 2023-01-16 16:21:12 +01:00
Tony Garnock-Jones 0f5e033174 noise 2023-01-16 15:52:46 +01:00
Tony Garnock-Jones aae53b5525 Update precompiled form 2023-01-16 15:51:57 +01:00
Tony Garnock-Jones 4c03646567 HTTP 2022-12-13 18:08:34 +13:00
Tony Garnock-Jones a7b5c69000 Version 0.8.5 2022-07-22 17:02:41 +02:00
Tony Garnock-Jones 3187c4642b Merge latest changes from the syndicate-protocols repository 2022-02-04 20:51:34 +01:00
Tony Garnock-Jones ca92d99c52 Remove notion of "system-layer-service" from core protocols 2022-02-04 14:26:50 +01:00
Tony Garnock-Jones 19c96bdef2 Allow userDefined states 2022-02-03 22:55:06 +01:00
Tony Garnock-Jones ab34b62cf1 Refine the trace protocol a bit 2022-01-20 09:40:53 +01:00
Tony Garnock-Jones 5a65256cf3 Syndicate traces 2022-01-19 14:24:21 +01:00
Tony Garnock-Jones 287a2903a7 Merge latest changes from the syndicate-protocols repository 2022-01-17 00:22:44 +01:00
Tony Garnock-Jones 257c604e2b Repair bad record pattern 2022-01-17 00:22:10 +01:00
Tony Garnock-Jones d99d589dd1 Ignore extensions 2022-01-17 00:20:17 +01:00
Tony Garnock-Jones b4276065a0 Merge latest changes from the syndicate-protocols repository 2022-01-17 00:19:17 +01:00
Tony Garnock-Jones a06d532006 Extension point. Closes #2 2022-01-16 21:17:36 +01:00
Tony Garnock-Jones 592cffe019 Version 0.8.4 2022-01-12 14:09:23 +01:00
Tony Garnock-Jones 8007382db5 Make unquotes autoescaping; add patterns.unlit(p) 2022-01-12 14:09:05 +01:00
Tony Garnock-Jones 08bbc4661a Version 0.8.3 2022-01-12 12:25:13 +01:00
Tony Garnock-Jones 0e8aca8892 More general quoting 2022-01-12 12:24:56 +01:00
Tony Garnock-Jones 78eef4c388 Version 0.8.2 2022-01-12 11:05:41 +01:00
Tony Garnock-Jones 90e71a606e Experimental pattern (quasi)quoting 2022-01-12 11:05:25 +01:00
Tony Garnock-Jones 184363a9a9 Add missing return keywords 2022-01-12 11:05:10 +01:00
Tony Garnock-Jones 30d1c067e7 Version 0.8.1 2022-01-11 20:54:16 +01:00
Tony Garnock-Jones c0afd99e46 First stab at tackling issues involved in running Syndicate in a multi-threaded context 2022-01-11 20:53:59 +01:00
Tony Garnock-Jones 2b5a0cdf02 Avoid complications in cases where we start a syndicate actor as part of another application 2022-01-11 20:19:40 +01:00
Tony Garnock-Jones 6dcac58377 Repair packaging 2022-01-11 20:19:18 +01:00
Tony Garnock-Jones 0f4f6a1716 Version 0.8.0 2022-01-11 18:21:22 +01:00
Tony Garnock-Jones 4662cbefd6 turn.after 2022-01-11 18:20:49 +01:00
Tony Garnock-Jones 8af47f1a1f on_stop_or_crash 2022-01-11 18:20:39 +01:00
Tony Garnock-Jones 04d46585fd Simplify 2022-01-08 13:43:42 +01:00
Tony Garnock-Jones a813780e8d Fix inf.py 2022-01-07 16:04:45 +01:00
Tony Garnock-Jones e04b898c7f Adjustments to service.prs 2022-01-07 15:29:20 +01:00
Tony Garnock-Jones fdc8714fe8 Slightly different approach to exposing "implicit active turn" functionality 2021-12-25 17:14:26 -05:00
37 changed files with 954 additions and 319 deletions

11
.envrc
View File

@ -1,3 +1,8 @@
[ -d .venv ] || python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
if ! [ -d .venv ]
then
python3 -m venv .venv
. .venv/bin/activate
pip install -e '.[dev]'
else
. .venv/bin/activate
fi

View File

@ -1,3 +1,5 @@
PACKAGEVERSION := $(shell ./print-package-version)
all:
clean:
@ -6,18 +8,28 @@ clean:
rm -f .coverage
rm -rf *.egg-info build dist
# sudo apt install python3-wheel twine
publish: build
tag:
git tag v$(PACKAGEVERSION)
publish: clean build
twine upload dist/*
build: clean
python3 setup.py sdist bdist_wheel
build: build-only
build-only: dist/syndicate-py-$(PACKAGEVERSION).tar.gz
dist/syndicate-py-$(PACKAGEVERSION).tar.gz:
python3 -m build
veryclean: clean
rm -rf pyenv
rm -rf .venv
PROTOCOLS_BRANCH=main
pull-protocols:
git subtree pull -P syndicate/protocols \
-m 'Merge latest changes from the syndicate-protocols repository' \
git@git.syndicate-lang.org:syndicate-lang/syndicate-protocols \
main
$(PROTOCOLS_BRANCH)
chat.bin: chat.prs
preserves-schemac .:chat.prs > $@

View File

@ -8,9 +8,13 @@ or
git clone https://git.syndicate-lang.org/syndicate-lang/syndicate-py
cd syndicate-py
virtualenv -p python3 pyenv
. pyenv/bin/activate
pip install -r requirements.txt
python -m venv .venv
. .venv/bin/activate
pip install -e '.[dev]'
See also
[syndicate-py-packaging](https://git.syndicate-lang.org/syndicate-lang/syndicate-py-packaging)
for Debian packaging scripts.
## Running
@ -19,10 +23,10 @@ Start a Syndicate broker (such as
Find the line of broker output giving the root capability:
... rootcap=<ref "syndicate" [] #x"a6480df5306611ddd0d3882b546e1977"> ...
... rootcap=<ref {oid: "syndicate" sig: #x"69ca300c1dbfa08fba692102dd82311a"}> ...
Then, run [chat.py](chat.py) several times in several separate windows:
python chat.py \
--address '<tcp "localhost" 8001>' \
--cap '<ref "syndicate" [] #x"a6480df5306611ddd0d3882b546e1977">'
--cap '<ref {oid: "syndicate" sig: #x"69ca300c1dbfa08fba692102dd82311a"}>'

View File

@ -14,7 +14,7 @@ parser.add_argument('--address', metavar='\'<tcp "HOST" PORT>\'',
default='<ws "ws://localhost:9001/">')
parser.add_argument('--cap', metavar='\'<ref ...>\'',
help='capability for the dataspace on the server',
default='<ref "syndicate" [] #[pkgN9TBmEd3Q04grVG4Zdw==]>')
default='<ref "syndicate" [] #[acowDB2/oI+6aSEC3YIxGg==]>')
parser.add_argument('--start',
help='make this instance kick off the procedure',
action='store_true')
@ -44,13 +44,13 @@ args = parser.parse_args()
#
# Here's a trace from a live session of this running against syndicate-rs:
#
# B --> server: [[1, <assert <Boot #!⌜141/402:00007f3e50021ef0⌝> 3>]]
# B --> server: [[1, <assert <Boot #:⌜141/402:00007f3e50021ef0⌝> 3>]]
#
# A --> server: [[1, <assert <Observe <rec Boot [<bind <_>>]> #!⌜151/422:00007f3e50025090⌝> 3>]]
# A <-- server: [[1, <assert [#!⌜141/402:00007f3e50021ef0⌝] 633>]]
# A --> server: [[2, <assert <One #!⌜151/422:00007f3e5c009b00⌝> 5>]]
# A --> server: [[1, <assert <Observe <rec Boot [<bind <_>>]> #:⌜151/422:00007f3e50025090⌝> 3>]]
# A <-- server: [[1, <assert [#:⌜141/402:00007f3e50021ef0⌝] 633>]]
# A --> server: [[2, <assert <One #:⌜151/422:00007f3e5c009b00⌝> 5>]]
#
# B <-- server: [[1, <assert <One #!⌜151/422:00007f3e5c009b00⌝> 643>]]
# B <-- server: [[1, <assert <One #:⌜151/422:00007f3e5c009b00⌝> 643>]]
# B --> server: [[1, <retract 3>], [2, <assert <Two> 5>]]
#
# A <-- server: [[2, <assert <Two> 653>]]

1
chat.bin Normal file
View File

@ -0,0 +1 @@
´³bundle·µ³chat„´³schema·³version°³ definitions·³Says´³rec´³lit³Says„´³tupleµ´³named³who´³atom³String„„´³named³what´³atom³String„„„„„³Present´³rec´³lit³Present„´³tupleµ´³named³username´³atom³String„„„„„„³ embeddedType€„„„„

View File

@ -1,5 +1,4 @@
version 1 .
embeddedType EntityRef.Cap .
Present = <Present @username string>.
Says = <Says @who string @what string>.

13
chat.py
View File

@ -4,7 +4,11 @@ import asyncio
import random
import syndicate
from syndicate import patterns as P, actor, dataspace, turn
from syndicate.schema import simpleChatProtocol, sturdy
from syndicate.schema import sturdy
from preserves.schema import load_schema_file
simpleChatProtocol = load_schema_file('./chat.bin').chat
parser = argparse.ArgumentParser(description='Simple dataspace-server-mediated text chat.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
@ -13,7 +17,7 @@ parser.add_argument('--address', metavar='\'<tcp "HOST" PORT>\'',
default='<ws "ws://localhost:9001/">')
parser.add_argument('--cap', metavar='\'<ref ...>\'',
help='capability for the dataspace on the server',
default='<ref "syndicate" [] #[pkgN9TBmEd3Q04grVG4Zdw==]>')
default='<ref {oid: "syndicate" sig: #[acowDB2/oI+6aSEC3YIxGg==]}>')
args = parser.parse_args()
Present = simpleChatProtocol.Present
@ -25,6 +29,8 @@ def main():
@syndicate.relay.connect(args.address, sturdy.SturdyRef.decode(syndicate.parse(args.cap)))
def on_connected(ds):
turn.on_stop(lambda: turn.stop(root_facet))
me = 'user_' + str(random.randint(10, 1000))
turn.publish(ds, Present(me))
@ -41,7 +47,6 @@ def main():
@turn.linked_task()
async def accept_input(f):
reader = asyncio.StreamReader()
await actor.find_loop().connect_read_pipe(lambda: asyncio.StreamReaderProtocol(reader), sys.stdin)
await f.loop.connect_read_pipe(lambda: asyncio.StreamReaderProtocol(reader), sys.stdin)
while line := (await reader.readline()).decode('utf-8'):
turn.external(f, lambda: turn.send(ds, Says(me, line.strip())))
turn.external(f, lambda: turn.stop(root_facet))

3
chat.server-config.pr Normal file
View File

@ -0,0 +1,3 @@
let ?root_ds = dataspace
<require-service <relay-listener <tcp "0.0.0.0" 9001> $gatekeeper>>
<bind <ref { oid: "syndicate" key: #x"" }> $root_ds #f>

4
inf.py
View File

@ -1,4 +1,4 @@
from syndicate import relay, Turn
from syndicate import relay, turn
from syndicate.during import During
import logging
@ -6,4 +6,4 @@ import logging
@During().add_handler
def main(args):
logging.info(f'in main {args}')
Turn.active.on_stop(lambda: logging.info(f'args retracted {args}'))
turn.on_stop(lambda: logging.info(f'args retracted {args}'))

9
inf.server-config.pr Normal file
View File

@ -0,0 +1,9 @@
<require-service <daemon inf>>
<daemon inf {
argv: "python inf.py"
protocol: application/syndicate
}>
? <service-object <daemon inf> ?cap> [
$cap += =here-is-your-configuration!
$cap += =here-is-another-configuration!
]

5
print-package-version Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
cd "$(dirname "$0")"
. ./.envrc
exec python -c \
'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])'

50
pyproject.toml Normal file
View File

@ -0,0 +1,50 @@
[project]
name = "syndicate-py"
version = "0.19.1"
description = "Syndicated Actor model and Syndicate network protocol for Python 3"
readme = "README.md"
requires-python = ">=3.6, <4"
license = {text = "GPL-3.0-or-later"}
authors = [
{name = "Tony Garnock-Jones", email = "tonyg@leastfixedpoint.com"},
]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Programming Language :: Python :: 3",
]
# "websockets" isn't listed here, but if you want to use relay.WebsocketTunnelRelay,
# you will need it.
dependencies = [
"preserves",
]
[project.urls]
Homepage = "https://git.syndicate-lang.org/syndicate-lang/syndicate-py"
Issues = "https://git.syndicate-lang.org/syndicate-lang/syndicate-py/issues"
[project.optional-dependencies]
dev = [
"build",
"twine",
]
[tool.setuptools]
packages = [
"syndicate",
"syndicate.protocols",
"syndicate.protocols.schemas",
]
[tool.setuptools.package-data]
"syndicate.protocols" = ["*.bin"]
"syndicate.protocols.schemas" = ["*.prs"]
[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"

View File

@ -1,2 +0,0 @@
websockets
preserves

View File

@ -1,26 +0,0 @@
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
setup(
name="syndicate-py",
version="0.7.1",
author="Tony Garnock-Jones",
author_email="tonyg@leastfixedpoint.com",
license="GNU General Public License v3 or later (GPLv3+)",
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Programming Language :: Python :: 3",
],
packages=["syndicate"],
url="https://git.syndicate-lang.org/syndicate-lang/syndicate-py",
description="Syndicated Actor model and Syndicate network protocol for Python 3",
install_requires=['websockets', 'preserves'],
python_requires=">=3.6, <4",
setup_requires=['setuptools_scm'],
include_package_data=True,
)

View File

@ -3,4 +3,48 @@ __path__ = __import__('pkgutil').extend_path(__path__, __name__)
# This is 'import *' in order to effectively re-export preserves as part of this module's API.
from preserves import *
def __setup():
from .actor import _active, Turn
from .metapy import staticproperty
from types import FunctionType
import sys
class turn:
@staticproperty
def active():
t = getattr(_active, 'turn', False)
if t is False:
t = _active.turn = None
return t
@staticproperty
def log():
return turn.active.log
def run(facet, action):
return Turn.run(facet, action)
def external(facet, action, loop=None):
return Turn.external(facet, action, loop=loop)
def active_facet():
return turn.active._facet
def install_definition(name, definition):
def handler(*args, **kwargs):
return definition(turn.active, *args, **kwargs)
setattr(turn, name, handler)
for (name, definition) in Turn.__dict__.items():
if name[0] == '_':
continue
elif type(definition) == FunctionType:
install_definition(name, definition)
else:
pass
return turn
turn = __setup()
from . import relay

View File

@ -22,29 +22,62 @@ _active.turn = None
# decorator
def run_system(**kwargs):
return lambda boot_proc: start_actor_system(boot_proc, **kwargs)
return lambda boot_proc: System().run(boot_proc, **kwargs)
def start_actor_system(boot_proc, debug = False, name = None, configure_logging = True):
if configure_logging:
logging.basicConfig(level = logging.DEBUG if debug else logging.INFO)
loop = asyncio.get_event_loop()
if debug:
loop.set_debug(True)
queue_task(lambda: Actor(boot_proc, name = name), loop = loop)
loop.run_forever()
while asyncio.all_tasks(loop):
loop.stop()
loop.run_forever()
loop.close()
class System:
def __init__(self, loop = None):
self.loop = loop or asyncio.get_event_loop()
self.inhabitant_count = 0
self.exit_signal = asyncio.Queue()
def adjust_engine_inhabitant_count(delta):
loop = asyncio.get_running_loop()
if not hasattr(loop, '__syndicate_inhabitant_count'):
loop.__syndicate_inhabitant_count = 0
loop.__syndicate_inhabitant_count = loop.__syndicate_inhabitant_count + delta
if loop.__syndicate_inhabitant_count == 0:
log.debug('Inhabitant count reached zero')
loop.stop()
def run(self, boot_proc, debug = None, name = None, configure_logging = True):
if configure_logging:
logging.basicConfig(level = logging.DEBUG if debug else logging.INFO)
if debug:
self.loop.set_debug(True)
self.queue_task(lambda: Actor(boot_proc, system = self, name = name))
# From Python 3.12, we may be able to use:
# asyncio.run(self._run, debug=debug, loop_factory=lambda: self.loop)
# but until then:
with asyncio.Runner(debug=debug, loop_factory=lambda: self.loop) as r:
return r.run(self._run())
async def _run(self):
try:
await self.exit_signal.get()
except asyncio.CancelledError:
pass
finally:
log.debug('System._run main loop exit')
def adjust_engine_inhabitant_count(self, delta):
self.inhabitant_count = self.inhabitant_count + delta
if self.inhabitant_count == 0:
log.debug('Inhabitant count reached zero')
self.exit_signal.put_nowait(())
def queue_task(self, thunk):
async def task():
try:
await ensure_awaitable(thunk())
except asyncio.CancelledError:
pass
return self.loop.create_task(task())
def queue_task_threadsafe(self, thunk):
async def task():
try:
await ensure_awaitable(thunk())
except asyncio.CancelledError:
pass
return self.loop.call_soon_threadsafe(lambda: asyncio.run_coroutine_threadsafe(task(), self.loop))
async def ensure_awaitable(value):
if inspect.isawaitable(value):
return await value
else:
return value
def remove_noerror(collection, item):
try:
@ -53,11 +86,12 @@ def remove_noerror(collection, item):
pass
class Actor:
def __init__(self, boot_proc, name = None, initial_assertions = {}, daemon = False):
def __init__(self, boot_proc, system, name = None, initial_assertions = {}, daemon = False):
self.name = name or 'a' + str(next(_next_actor_number))
self._system = system
self._daemon = daemon
if not daemon:
adjust_engine_inhabitant_count(1)
system.adjust_engine_inhabitant_count(1)
self.root = Facet(self, None)
self.outbound = initial_assertions or {}
self.exit_reason = None # None -> running, True -> terminated OK, exn -> error
@ -77,7 +111,7 @@ class Actor:
def daemon(self, value):
if self._daemon != value:
self._daemon = value
adjust_engine_inhabitant_count(-1 if value else 1)
self._system.adjust_engine_inhabitant_count(-1 if value else 1)
@property
def alive(self):
@ -115,7 +149,7 @@ class Actor:
h()
self.root._terminate(exit_reason == True)
if not self._daemon:
adjust_engine_inhabitant_count(-1)
self._system.adjust_engine_inhabitant_count(-1)
def _pop_outbound(self, handle, clear_from_source_facet):
e = self.outbound.pop(handle)
@ -174,6 +208,15 @@ class Facet:
def cancel_on_stop(self, a):
remove_noerror(self.shutdown_actions, a)
def on_stop_or_crash(self, a):
def cleanup():
self.cancel_on_stop(cleanup)
self.actor.cancel_at_exit(cleanup)
a()
self.on_stop(cleanup)
self.actor.at_exit(cleanup)
return cleanup
def isinert(self):
return \
len(self.children) == 0 and \
@ -191,25 +234,41 @@ class Facet:
self.inert_check_preventers = self.inert_check_preventers - 1
return disarm
def linked_task(self, coro_fn, loop = None):
@property
def loop(self):
return self.actor._system.loop
def linked_task(self, coro_fn, run_in_executor=False):
task = None
if run_in_executor:
inner_coro_fn = coro_fn
async def outer_coro_fn(facet):
await self.loop.run_in_executor(None, lambda: inner_coro_fn(facet))
coro_fn = outer_coro_fn
@self.on_stop_or_crash
def cancel_linked_task():
nonlocal task
if task is not None:
remove_noerror(self.linked_tasks, task)
task.cancel()
task = None
self.cancel_on_stop(cancel_linked_task)
self.actor.cancel_at_exit(cancel_linked_task)
async def guarded_task():
should_terminate_facet = True
try:
await coro_fn(self)
if await coro_fn(self) is True:
should_terminate_facet = False
except asyncio.CancelledError:
pass
except:
import traceback
traceback.print_exc()
finally:
Turn.external(self, cancel_linked_task)
task = find_loop(loop).create_task(guarded_task())
if should_terminate_facet:
Turn.external(self, lambda: Turn.active.stop())
else:
Turn.external(self, cancel_linked_task)
task = self.loop.create_task(guarded_task())
self.linked_tasks.append(task)
self.on_stop(cancel_linked_task)
self.actor.at_exit(cancel_linked_task)
def _terminate(self, orderly):
if not self.alive: return
@ -256,29 +315,16 @@ class ActiveFacet:
self.turn._facet = self.outer_facet
self.outer_facet = None
async def ensure_awaitable(value):
if inspect.isawaitable(value):
return await value
else:
return value
def find_loop(loop = None):
return asyncio.get_running_loop() if loop is None else loop
def queue_task(thunk, loop = None):
async def task():
await ensure_awaitable(thunk())
return find_loop(loop).create_task(task())
def queue_task_threadsafe(thunk, loop = None):
async def task():
await ensure_awaitable(thunk())
return asyncio.run_coroutine_threadsafe(task(), find_loop(loop))
class Turn:
@staticproperty
def active():
return _active.turn
t = getattr(_active, 'turn', False)
if t is False:
t = _active.turn = None
return t
@classmethod
def run(cls, facet, action, zombie_turn = False):
@ -303,10 +349,11 @@ class Turn:
@classmethod
def external(cls, facet, action, loop = None):
return queue_task_threadsafe(lambda: cls.run(facet, action), loop)
return facet.actor._system.queue_task_threadsafe(lambda: cls.run(facet, action))
def __init__(self, facet):
self._facet = facet
self._system = facet.actor._system
self.queues = {}
@property
@ -327,23 +374,24 @@ class Turn:
return self._facet.prevent_inert_check()
# decorator
def linked_task(self, loop = None):
return lambda coro_fn: self._facet.linked_task(coro_fn, loop = loop)
def linked_task(self, **kwargs):
return lambda coro_fn: self._facet.linked_task(coro_fn, **kwargs)
def stop(self, facet = None, continuation = None):
if facet is None:
facet = self._facet
if facet.parent is None:
self.stop_actor()
else:
if continuation is not None:
facet.on_stop(continuation)
facet._terminate(True)
if continuation is not None:
facet.on_stop(continuation)
facet._terminate(True)
# can also be used as a decorator
def on_stop(self, a):
self._facet.on_stop(a)
# can also be used as a decorator
def on_stop_or_crash(self, a):
self._facet.on_stop_or_crash(a)
def spawn(self, boot_proc, name = None, initial_handles = None, daemon = False):
def action():
new_outbound = {}
@ -351,10 +399,11 @@ class Turn:
for handle in initial_handles:
new_outbound[handle] = \
self._facet.actor._pop_outbound(handle, clear_from_source_facet=True)
queue_task(lambda: Actor(boot_proc,
name = name,
initial_assertions = new_outbound,
daemon = daemon))
self._system.queue_task(lambda: Actor(boot_proc,
system = self._system,
name = name,
initial_assertions = new_outbound,
daemon = daemon))
self._enqueue(self._facet, action)
def stop_actor(self):
@ -444,6 +493,15 @@ class Turn:
ref.entity.on_message(message)
self._enqueue(ref.facet, action)
# decorator
def after(self, delay_seconds):
def decorate(action):
@self.linked_task()
async def task(facet):
await asyncio.sleep(delay_seconds)
Turn.external(facet, action)
return decorate
def _enqueue(self, target_facet, action):
target_actor = target_facet.actor
if target_actor not in self.queues:
@ -462,7 +520,7 @@ class Turn:
action()
turn._facet = saved_facet
return lambda: Turn.run(actor.root, deliver_q)
queue_task(make_deliver_q(actor, q))
self._system.queue_task(make_deliver_q(actor, q))
self.queues = {}
def stop_if_inert_after(action):
@ -533,5 +591,13 @@ def __boot_inert():
_inert_facet = Turn.active._facet
_inert_ref = Turn.active.ref(_inert_entity)
async def __run_inert():
Actor(__boot_inert, name = '_inert_actor')
asyncio.get_event_loop().run_until_complete(__run_inert())
Actor(__boot_inert, system = System(), name = '_inert_actor')
def __setup_inert():
def setup_main():
loop = asyncio.new_event_loop()
loop.run_until_complete(__run_inert())
loop.close()
t = threading.Thread(target=setup_main)
t.start()
t.join()
__setup_inert()

View File

@ -41,10 +41,13 @@ class Graph:
repaired_this_round = repaired_this_round | workset
updated_subjects = set()
for object_id in workset:
for subject_id in self.observers_of(object_id):
self.forget_subject(subject_id)
self.with_subject(subject_id, lambda: repair_fn(subject_id))
if subject_id not in updated_subjects:
updated_subjects.add(subject_id)
self.forget_subject(subject_id)
self.with_subject(subject_id, lambda: repair_fn(subject_id))
__nextFieldId = 0

View File

@ -5,8 +5,11 @@ from . import turn
# decorator
def resolve(gk, cap, *args, **kwargs):
def configure_handler(handler):
def unwrapping_handler(wrapped_ref):
return handler(wrapped_ref.embeddedValue)
def unwrapping_handler(r):
resolved = gatekeeper.Resolved.decode(r)
if resolved.VARIANT.name == 'accepted':
return handler(resolved.responderSession)
raise Exception('Could not resolve reference: ' + repr(resolved))
return _resolve(gk, cap)(During(*args, **kwargs).add_handler(unwrapping_handler))
return configure_handler

View File

@ -1,15 +1,55 @@
from .schema import dataspacePatterns as P
from . import Symbol, Record
from preserves import preserve
_dict = dict ## we're about to shadow the builtin
_ = P.Pattern.DDiscard(P.DDiscard())
_ = P.Pattern.discard()
def bind(p):
return P.Pattern.DBind(P.DBind(p))
return P.Pattern.bind(p)
CAPTURE = bind(_)
class unquote:
def __init__(self, pattern):
self.pattern = pattern
def __escape_schema__(self):
return self
uCAPTURE = unquote(CAPTURE)
u_ = unquote(_)
# Given
#
# Run = <run @name string @input any @output any>
#
# then these all produce the same pattern:
#
# P.rec('Observe', P.quote(P.rec('run', P.lit('N'), P.uCAPTURE, P.bind(P.u_))), P._)
#
# P.rec('Observe', P.quote(P.quote(Run('N', P.unquote(P.uCAPTURE), P.unquote(P.bind(P.u_))))), P._)
#
# P.quote(Record(Symbol('Observe'),
# [P.quote(Run('N', P.unquote(P.uCAPTURE), P.unquote(P.bind(P.u_)))),
# P.u_]))
# Simple, stupid single-level quasiquotation.
def quote(p):
if isinstance(p, unquote):
return p.pattern
p = preserve(p)
if isinstance(p, list) or isinstance(p, tuple):
return arr(*map(quote, p))
elif isinstance(p, set) or isinstance(p, frozenset):
raise Exception('Cannot represent literal set in dataspace pattern')
elif isinstance(p, _dict):
return dict(*((k, quote(pp)) for (k, pp) in p.items()))
elif isinstance(p, Record):
return _rec(p.key, *map(quote, p.fields))
else:
return P.Pattern.lit(P.AnyAtom.decode(p))
def lit(v):
if isinstance(v, list) or isinstance(v, tuple):
return arr(*map(lit, v))
@ -20,16 +60,52 @@ def lit(v):
elif isinstance(v, Record):
return _rec(v.key, *map(lit, v.fields))
else:
return P.Pattern.DLit(P.DLit(P.AnyAtom.decode(v)))
return P.Pattern.lit(P.AnyAtom.decode(v))
def seq_entries(seq):
entries = {}
for i, p in enumerate(seq):
if p.VARIANT != P.Pattern.discard.VARIANT:
entries[i] = p
np = len(seq)
if np > 0 and (np - 1) not in entries:
entries[np - 1] = P.Pattern.discard()
return entries
def unlit_seq(entries):
seq = []
if len(entries) > 0:
try:
max_k = max(entries.keys())
except TypeError:
raise Exception('Pattern entries do not represent a gap-free sequence')
for i in range(max_k + 1):
seq.append(unlit(entries[i]))
return seq
def unlit(p):
if not hasattr(p, 'VARIANT'):
p = P.Pattern.decode(p)
if p.VARIANT == P.Pattern.lit.VARIANT:
return p.value.value
if p.VARIANT != P.Pattern.group.VARIANT:
raise Exception('Pattern does not represent a literal value')
if p.type.VARIANT == P.GroupType.rec.VARIANT:
return Record(p.type.label, unlit_seq(p.entries))
if p.type.VARIANT == P.GroupType.arr.VARIANT:
return list(unlit_seq(p.entries))
if p.type.VARIANT == P.GroupType.dict.VARIANT:
return _dict(map(lambda kv: (kv[0], unlit(kv[1])), p.entries.items()))
raise Exception('unreachable')
def rec(labelstr, *members):
return _rec(Symbol(labelstr), *members)
def _rec(label, *members):
return P.Pattern.DCompound(P.DCompound.rec(label, members))
return P.Pattern.group(P.GroupType.rec(label), seq_entries(members))
def arr(*members):
return P.Pattern.DCompound(P.DCompound.arr(members))
return P.Pattern.group(P.GroupType.arr(), seq_entries(members))
def dict(*kvs):
return P.Pattern.DCompound(P.DCompound.dict(_dict(kvs)))
return P.Pattern.group(P.GroupType.dict(), _dict(kvs))

View File

@ -1,17 +1,44 @@
´³bundle·µ³tcp„´³schema·³version³ definitions·³TcpLocal´³rec´³lit³ tcp-local„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³ TcpRemote´³rec´³lit³
tcp-remote„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³ TcpPeerInfo´³rec´³lit³tcp-peer„´³tupleµ´³named³handle´³embedded³any„„´³named³local´³refµ„³TcpLocal„„´³named³remote´³refµ„³ TcpRemote„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³timer„´³schema·³version³ definitions·³SetTimer´³rec´³lit³ set-timer„´³tupleµ´³named³label³any„´³named³msecs´³atom³Double„„´³named³kind´³refµ„³ TimerKind„„„„„³ LaterThan´³rec´³lit³
later-than„´³tupleµ´³named³msecs´³atom³Double„„„„„³ TimerKind´³orµµ±relative´³lit³relative„„µ±absolute´³lit³absolute„„µ±clear´³lit³clear„„„„³ TimerExpired´³rec´³lit³ timer-expired„´³tupleµ´³named³label³any„´³named³msecs´³atom³Double„„„„„„³ embeddedType€„„µ³stream„´³schema·³version³ definitions·³Mode´³orµµ±bytes´³lit³bytes„„µ±lines´³refµ„³LineMode„„µ±packet´³rec´³lit³packet„´³tupleµ´³named³size´³atom³ SignedInteger„„„„„„µ±object´³rec´³lit³object„´³tupleµ´³named³ description³any„„„„„„„³Sink´³orµµ±source´³rec´³lit³source„´³tupleµ´³named³
´³bundle·µ³tcp„´³schema·³version°³ definitions·³TcpLocal´³rec´³lit³ tcp-local„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³ TcpRemote´³rec´³lit³
tcp-remote„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³ TcpPeerInfo´³rec´³lit³tcp-peer„´³tupleµ´³named³handle´³embedded³any„„´³named³local´³refµ„³TcpLocal„„´³named³remote´³refµ„³ TcpRemote„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³http„´³schema·³version°³ definitions·³Chunk´³orµµ±string´³atom³String„„µ±bytes´³atom³
ByteString„„„„³Headers´³dictof´³atom³Symbol„´³atom³String„„³MimeType´³atom³Symbol„³
QueryValue´³orµµ±string´³atom³String„„µ±file´³rec´³lit³file„´³tupleµ´³named³filename´³atom³String„„´³named³headers´³refµ„³Headers„„´³named³body´³atom³
ByteString„„„„„„„„³ HostPattern´³orµµ±host´³atom³String„„µ±any´³lit€„„„„³ HttpBinding´³rec´³lit³ http-bind„´³tupleµ´³named³host´³refµ„³ HostPattern„„´³named³port´³atom³ SignedInteger„„´³named³method´³refµ„³ MethodPattern„„´³named³path´³refµ„³ PathPattern„„´³named³handler´³embedded´³refµ„³ HttpRequest„„„„„„³ HttpContext´³rec´³lit³request„´³tupleµ´³named³req´³refµ„³ HttpRequest„„´³named³res´³embedded´³refµ„³ HttpResponse„„„„„„³ HttpRequest´³rec´³lit³ http-request„´³tupleµ´³named³sequenceNumber´³atom³ SignedInteger„„´³named³host´³refµ„³ RequestHost„„´³named³port´³atom³ SignedInteger„„´³named³method´³atom³Symbol„„´³named³path´³seqof´³atom³String„„„´³named³headers´³refµ„³Headers„„´³named³query´³dictof´³atom³Symbol„´³seqof´³refµ„³
QueryValue„„„„´³named³body´³refµ„³ RequestBody„„„„„³ HttpService´³rec´³lit³ http-service„´³tupleµ´³named³host´³refµ„³ HostPattern„„´³named³port´³atom³ SignedInteger„„´³named³method´³refµ„³ MethodPattern„„´³named³path´³refµ„³ PathPattern„„„„„³ PathPattern´³seqof´³refµ„³PathPatternElement„„³ RequestBody´³orµµ±absent´³lit€„„µ±present´³atom³
ByteString„„„„³ RequestHost´³orµµ±absent´³lit€„„µ±present´³atom³String„„„„³ HttpListener´³rec´³lit³ http-listener„´³tupleµ´³named³port´³atom³ SignedInteger„„„„„³ HttpResponse´³orµµ±status´³rec´³lit³status„´³tupleµ´³named³code´³atom³ SignedInteger„„´³named³message´³atom³String„„„„„„µ±header´³rec´³lit³header„´³tupleµ´³named³name´³atom³Symbol„„´³named³value´³atom³String„„„„„„µ±chunk´³rec´³lit³chunk„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„µ±done´³rec´³lit³done„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„„„³ MethodPattern´³orµµ±any´³lit€„„µ±specific´³atom³Symbol„„„„³PathPatternElement´³orµµ±label´³atom³String„„µ±wildcard´³lit³_„„µ±rest´³lit³...„„„„„³ embeddedType€„„µ³noise„´³schema·³version°³ definitions·³Packet´³orµµ±complete´³atom³
ByteString„„µ±
fragmented´³seqof´³atom³
ByteString„„„„„³ Initiator´³rec´³lit³ initiator„´³tupleµ´³named³initiatorSession´³embedded´³refµ„³Packet„„„„„„³ NoiseSpec´³andµ´³dict·³key´³named³key´³atom³
ByteString„„³service´³named³service´³refµ„³ServiceSelector„„„„´³named³protocol´³refµ„³ NoiseProtocol„„´³named³ preSharedKeys´³refµ„³NoisePreSharedKeys„„„„³ SessionItem´³orµµ± Initiator´³refµ„³ Initiator„„µ±Packet´³refµ„³Packet„„„„³ NoiseProtocol´³orµµ±present´³dict·³protocol´³named³protocol´³atom³String„„„„„µ±invalid´³dict·³protocol´³named³protocol³any„„„„µ±absent´³dict·„„„„„³ NoiseStepType´³lit³noise„³SecretKeyField´³orµµ±present´³dict·³ secretKey´³named³ secretKey´³atom³
ByteString„„„„„µ±invalid´³dict·³ secretKey´³named³ secretKey³any„„„„µ±absent´³dict·„„„„„³DefaultProtocol´³lit±!Noise_NK_25519_ChaChaPoly_BLAKE2s„³NoiseStepDetail´³refµ„³ServiceSelector„³ServiceSelector³any³NoiseServiceSpec´³andµ´³named³base´³refµ„³ NoiseSpec„„´³named³ secretKey´³refµ„³SecretKeyField„„„„³NoisePreSharedKeys´³orµµ±present´³dict·³ preSharedKeys´³named³ preSharedKeys´³seqof´³atom³
ByteString„„„„„„µ±invalid´³dict·³ preSharedKeys´³named³ preSharedKeys³any„„„„µ±absent´³dict·„„„„„³NoisePathStepDetail´³refµ„³ NoiseSpec„³NoiseDescriptionDetail´³refµ„³NoiseServiceSpec„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³timer„´³schema·³version°³ definitions·³SetTimer´³rec´³lit³ set-timer„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„´³named³kind´³refµ„³ TimerKind„„„„„³ LaterThan´³rec´³lit³
later-than„´³tupleµ´³named³seconds´³atom³Double„„„„„³ TimerKind´³orµµ±relative´³lit³relative„„µ±absolute´³lit³absolute„„µ±clear´³lit³clear„„„„³ TimerExpired´³rec´³lit³ timer-expired„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„„„„„³ embeddedType€„„µ³trace„´³schema·³version°³ definitions·³Oid³any³Name´³orµµ± anonymous´³rec´³lit³ anonymous„´³tupleµ„„„„µ±named´³rec´³lit³named„´³tupleµ´³named³name³any„„„„„„„³Target´³rec´³lit³entity„´³tupleµ´³named³actor´³refµ„³ActorId„„´³named³facet´³refµ„³FacetId„„´³named³oid´³refµ„³Oid„„„„„³TaskId³any³TurnId³any³ActorId³any³FacetId³any³ TurnCause´³orµµ±turn´³rec´³lit³ caused-by„´³tupleµ´³named³id´³refµ„³TurnId„„„„„„µ±cleanup´³rec´³lit³cleanup„´³tupleµ„„„„µ±linkedTaskRelease´³rec´³lit³linked-task-release„´³tupleµ´³named³id´³refµ„³TaskId„„´³named³reason´³refµ„³LinkedTaskReleaseReason„„„„„„µ±periodicActivation´³rec´³lit³periodic-activation„´³tupleµ´³named³period´³atom³Double„„„„„„µ±delay´³rec´³lit³delay„´³tupleµ´³named³ causingTurn´³refµ„³TurnId„„´³named³amount´³atom³Double„„„„„„µ±external´³rec´³lit³external„´³tupleµ´³named³ description³any„„„„„„„³ TurnEvent´³orµµ±assert´³rec´³lit³assert„´³tupleµ´³named³ assertion´³refµ„³AssertionDescription„„´³named³handle´³refµ³protocol„³Handle„„„„„„µ±retract´³rec´³lit³retract„´³tupleµ´³named³handle´³refµ³protocol„³Handle„„„„„„µ±message´³rec´³lit³message„´³tupleµ´³named³body´³refµ„³AssertionDescription„„„„„„µ±sync´³rec´³lit³sync„´³tupleµ´³named³peer´³refµ„³Target„„„„„„µ± breakLink´³rec´³lit³
break-link„´³tupleµ´³named³source´³refµ„³ActorId„„´³named³handle´³refµ³protocol„³Handle„„„„„„„„³
ExitStatus´³orµµ±ok´³lit³ok„„µ±Error´³refµ³protocol„³Error„„„„³
TraceEntry´³rec´³lit³trace„´³tupleµ´³named³ timestamp´³atom³Double„„´³named³actor´³refµ„³ActorId„„´³named³item´³refµ„³ActorActivation„„„„„³ActorActivation´³orµµ±start´³rec´³lit³start„´³tupleµ´³named³ actorName´³refµ„³Name„„„„„„µ±turn´³refµ„³TurnDescription„„µ±stop´³rec´³lit³stop„´³tupleµ´³named³status´³refµ„³
ExitStatus„„„„„„„„³FacetStopReason´³orµµ±explicitAction´³lit³explicit-action„„µ±inert´³lit³inert„„µ±parentStopping´³lit³parent-stopping„„µ± actorStopping´³lit³actor-stopping„„„„³TurnDescription´³rec´³lit³turn„´³tupleµ´³named³id´³refµ„³TurnId„„´³named³cause´³refµ„³ TurnCause„„´³named³actions´³seqof´³refµ„³ActionDescription„„„„„„³ActionDescription´³orµµ±dequeue´³rec´³lit³dequeue„´³tupleµ´³named³event´³refµ„³TargetedTurnEvent„„„„„„µ±enqueue´³rec´³lit³enqueue„´³tupleµ´³named³event´³refµ„³TargetedTurnEvent„„„„„„µ±dequeueInternal´³rec´³lit³dequeue-internal„´³tupleµ´³named³event´³refµ„³TargetedTurnEvent„„„„„„µ±enqueueInternal´³rec´³lit³enqueue-internal„´³tupleµ´³named³event´³refµ„³TargetedTurnEvent„„„„„„µ±spawn´³rec´³lit³spawn„´³tupleµ´³named³link´³atom³Boolean„„´³named³id´³refµ„³ActorId„„„„„„µ±link´³rec´³lit³link„´³tupleµ´³named³ parentActor´³refµ„³ActorId„„´³named³ childToParent´³refµ³protocol„³Handle„„´³named³
childActor´³refµ„³ActorId„„´³named³ parentToChild´³refµ³protocol„³Handle„„„„„„µ±
facetStart´³rec´³lit³ facet-start„´³tupleµ´³named³path´³seqof´³refµ„³FacetId„„„„„„„µ± facetStop´³rec´³lit³
facet-stop„´³tupleµ´³named³path´³seqof´³refµ„³FacetId„„„´³named³reason´³refµ„³FacetStopReason„„„„„„µ±linkedTaskStart´³rec´³lit³linked-task-start„´³tupleµ´³named³taskName´³refµ„³Name„„´³named³id´³refµ„³TaskId„„„„„„„„³TargetedTurnEvent´³rec´³lit³event„´³tupleµ´³named³target´³refµ„³Target„„´³named³detail´³refµ„³ TurnEvent„„„„„³AssertionDescription´³orµµ±value´³rec´³lit³value„´³tupleµ´³named³value³any„„„„„µ±opaque´³rec´³lit³opaque„´³tupleµ´³named³ description³any„„„„„„„³LinkedTaskReleaseReason´³orµµ± cancelled´³lit³ cancelled„„µ±normal´³lit³normal„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³stdenv„´³schema·³version°³ definitions·³ StandardRoute´³orµµ±standard´³ tuplePrefixµ´³named³
transports´³seqof´³refµ„³StandardTransport„„„´³named³key´³atom³
ByteString„„´³named³service³any„´³named³sig´³atom³
ByteString„„´³named³oid³any„„´³named³caveats´³seqof´³refµ³sturdy„³Caveat„„„„„µ±general´³refµ³
gatekeeper„³Route„„„„³StandardTransport´³orµµ±wsUrl´³atom³String„„µ±other³any„„„„³ embeddedType€„„µ³stream„´³schema·³version°³ definitions·³Mode´³orµµ±bytes´³lit³bytes„„µ±lines´³refµ„³LineMode„„µ±packet´³rec´³lit³packet„´³tupleµ´³named³size´³atom³ SignedInteger„„„„„„µ±object´³rec´³lit³object„´³tupleµ´³named³ description³any„„„„„„„³Sink´³orµµ±source´³rec´³lit³source„´³tupleµ´³named³
controller´³embedded´³refµ„³Source„„„„„„„µ± StreamError´³refµ„³ StreamError„„µ±data´³rec´³lit³data„´³tupleµ´³named³payload³any„´³named³mode´³refµ„³Mode„„„„„„µ±eof´³rec´³lit³eof„´³tupleµ„„„„„„³Source´³orµµ±sink´³rec´³lit³sink„´³tupleµ´³named³
controller´³embedded´³refµ„³Sink„„„„„„„µ± StreamError´³refµ„³ StreamError„„µ±credit´³rec´³lit³credit„´³tupleµ´³named³amount´³refµ„³ CreditAmount„„´³named³mode´³refµ„³Mode„„„„„„„„³LineMode´³orµµ±lf´³lit³lf„„µ±crlf´³lit³crlf„„„„³ StreamError´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„„„„³ CreditAmount´³orµµ±count´³atom³ SignedInteger„„µ± unbounded´³lit³ unbounded„„„„³StreamConnection´³rec´³lit³stream-connection„´³tupleµ´³named³source´³embedded´³refµ„³Source„„„´³named³sink´³embedded´³refµ„³Sink„„„´³named³spec³any„„„„³StreamListenerError´³rec´³lit³stream-listener-error„´³tupleµ´³named³spec³any„´³named³message´³atom³String„„„„„³StreamListenerReady´³rec´³lit³stream-listener-ready„´³tupleµ´³named³spec³any„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³sturdy„´³schema·³version³ definitions·³Lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„³Oid´³atom³ SignedInteger„³Alts´³rec´³lit³or„´³tupleµ´³named³ alternatives´³seqof´³refµ„³Rewrite„„„„„„³PAnd´³rec´³lit³and„´³tupleµ´³named³patterns´³seqof´³refµ„³Pattern„„„„„„³PNot´³rec´³lit³not„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³TRef´³rec´³lit³ref„´³tupleµ´³named³binding´³atom³ SignedInteger„„„„„³PAtom´³orµµ±Boolean´³lit³Boolean„„µ±Float´³lit³Float„„µ±Double´³lit³Double„„µ± SignedInteger´³lit³ SignedInteger„„µ±String´³lit³String„„µ±
controller´³embedded´³refµ„³Sink„„„„„„„µ± StreamError´³refµ„³ StreamError„„µ±credit´³rec´³lit³credit„´³tupleµ´³named³amount´³refµ„³ CreditAmount„„´³named³mode´³refµ„³Mode„„„„„„„„³LineMode´³orµµ±lf´³lit³lf„„µ±crlf´³lit³crlf„„„„³ StreamError´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„„„„³ CreditAmount´³orµµ±count´³atom³ SignedInteger„„µ± unbounded´³lit³ unbounded„„„„³StreamConnection´³rec´³lit³stream-connection„´³tupleµ´³named³source´³embedded´³refµ„³Source„„„´³named³sink´³embedded´³refµ„³Sink„„„´³named³spec³any„„„„³StreamListenerError´³rec´³lit³stream-listener-error„´³tupleµ´³named³spec³any„´³named³message´³atom³String„„„„„³StreamListenerReady´³rec´³lit³stream-listener-ready„´³tupleµ´³named³spec³any„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³sturdy„´³schema·³version°³ definitions·³Lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„³Oid´³atom³ SignedInteger„³Alts´³rec´³lit³or„´³tupleµ´³named³ alternatives´³seqof´³refµ„³Rewrite„„„„„„³PAnd´³rec´³lit³and„´³tupleµ´³named³patterns´³seqof´³refµ„³Pattern„„„„„„³PNot´³rec´³lit³not„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³TRef´³rec´³lit³ref„´³tupleµ´³named³binding´³atom³ SignedInteger„„„„„³PAtom´³orµµ±Boolean´³lit³Boolean„„µ±Double´³lit³Double„„µ± SignedInteger´³lit³ SignedInteger„„µ±String´³lit³String„„µ±
ByteString´³lit³
ByteString„„µ±Symbol´³lit³Symbol„„„„³PBind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³Caveat´³orµµ±Rewrite´³refµ„³Rewrite„„µ±Alts´³refµ„³Alts„„„„³Pattern´³orµµ±PDiscard´³refµ„³PDiscard„„µ±PAtom´³refµ„³PAtom„„µ± PEmbedded´³refµ„³ PEmbedded„„µ±PBind´³refµ„³PBind„„µ±PAnd´³refµ„³PAnd„„µ±PNot´³refµ„³PNot„„µ±Lit´³refµ„³Lit„„µ± PCompound´³refµ„³ PCompound„„„„³Rewrite´³rec´³lit³rewrite„´³tupleµ´³named³pattern´³refµ„³Pattern„„´³named³template´³refµ„³Template„„„„„³WireRef´³orµµ±mine´³tupleµ´³lit<69>´³named³oid´³refµ„³Oid„„„„„µ±yours´³ tuplePrefixµ´³lit´³named³oid´³refµ„³Oid„„„´³named³ attenuation´³seqof´³refµ„³Caveat„„„„„„„³PDiscard´³rec´³lit³_„´³tupleµ„„„³Template´³orµµ±
ByteString„„µ±Symbol´³lit³Symbol„„„„³PBind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³Caveat´³orµµ±Rewrite´³refµ„³Rewrite„„µ±Alts´³refµ„³Alts„„µ±Reject´³refµ„³Reject„„µ±unknown³any„„„³Reject´³rec´³lit³reject„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³Pattern´³orµµ±PDiscard´³refµ„³PDiscard„„µ±PAtom´³refµ„³PAtom„„µ± PEmbedded´³refµ„³ PEmbedded„„µ±PBind´³refµ„³PBind„„µ±PAnd´³refµ„³PAnd„„µ±PNot´³refµ„³PNot„„µ±Lit´³refµ„³Lit„„µ± PCompound´³refµ„³ PCompound„„„„³Rewrite´³rec´³lit³rewrite„´³tupleµ´³named³pattern´³refµ„³Pattern„„´³named³template´³refµ„³Template„„„„„³WireRef´³orµµ±mine´³tupleµ´³lit°„´³named³oid´³refµ„³Oid„„„„„µ±yours´³ tuplePrefixµ´³lit°„´³named³oid´³refµ„³Oid„„„´³named³ attenuation´³seqof´³refµ„³Caveat„„„„„„„³PDiscard´³rec´³lit³_„´³tupleµ„„„³Template´³orµµ±
TAttenuate´³refµ„³
TAttenuate„„µ±TRef´³refµ„³TRef„„µ±Lit´³refµ„³Lit„„µ± TCompound´³refµ„³ TCompound„„„„³ PCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Pattern„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Pattern„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„³ PEmbedded´³lit³Embedded„³ SturdyRef´³rec´³lit³ref„´³tupleµ´³named³oid³any„´³named³ caveatChain´³seqof´³refµ„³ Attenuation„„„´³named³sig´³atom³
ByteString„„„„„³ TCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Template„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Template„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Template„„„„„„„„„³
TAttenuate´³rec´³lit³ attenuate„´³tupleµ´³named³template´³refµ„³Template„„´³named³ attenuation´³refµ„³ Attenuation„„„„„³ Attenuation´³seqof´³refµ„³Caveat„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³worker„´³schema·³version³ definitions·³Instance´³rec´³lit³Instance„´³tupleµ´³named³name´³atom³String„„´³named³argument³any„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³service„´³schema·³version³ definitions·³State´³orµµ±started´³lit³started„„µ±ready´³lit³ready„„µ±failed´³lit³failed„„µ±complete´³lit³complete„„„„³
RunService´³rec´³lit³ run-service„´³tupleµ´³named³ serviceName³any„„„„³ CoreService´³rec´³lit³ core-service„´³tupleµ´³named³ serviceName³any„„„„³ ServiceState´³rec´³lit³ service-state„´³tupleµ´³named³ serviceName³any„´³named³state´³refµ„³State„„„„„³ ServiceObject´³rec´³lit³service-object„´³tupleµ´³named³ serviceName³any„´³named³object³any„„„„³RequireService´³rec´³lit³require-service„´³tupleµ´³named³ serviceName³any„„„„³ServiceDependency´³rec´³lit³
depends-on„´³tupleµ´³named³depender³any„´³named³dependee´³refµ„³ ServiceState„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³protocol„´³schema·³version³ definitions·³Oid´³atom³ SignedInteger„³Sync´³rec´³lit³sync„´³tupleµ´³named³peer´³embedded´³lit<69>„„„„„„³Turn´³seqof´³refµ„³ TurnEvent„„³Error´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„´³named³detail³any„„„„³Event´³orµµ±Assert´³refµ„³Assert„„µ±Retract´³refµ„³Retract„„µ±Message´³refµ„³Message„„µ±Sync´³refµ„³Sync„„„„³Assert´³rec´³lit³assert„´³tupleµ´³named³ assertion´³refµ„³ Assertion„„´³named³handle´³refµ„³Handle„„„„„³Handle´³atom³ SignedInteger„³Packet´³orµµ±Turn´³refµ„³Turn„„µ±Error´³refµ„³Error„„„„³Message´³rec´³lit³message„´³tupleµ´³named³body´³refµ„³ Assertion„„„„„³Retract´³rec´³lit³retract„´³tupleµ´³named³handle´³refµ„³Handle„„„„„³ Assertion³any³ TurnEvent´³tupleµ´³named³oid´³refµ„³Oid„„´³named³event´³refµ„³Event„„„„„³ embeddedType€„„µ³ dataspace„´³schema·³version³ definitions·³Observe´³rec´³lit³Observe„´³tupleµ´³named³pattern´³refµ³dataspacePatterns„³Pattern„„´³named³observer´³embedded³any„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³
gatekeeper„´³schema·³version³ definitions·³Bind´³rec´³lit³bind„´³tupleµ´³named³oid³any„´³named³key´³atom³
ByteString„„´³named³target´³embedded³any„„„„„³Resolve´³rec´³lit³resolve„´³tupleµ´³named³ sturdyref´³refµ³sturdy„³ SturdyRef„„´³named³observer´³embedded´³embedded³any„„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³ racketEvent„´³schema·³version³ definitions·³ RacketEvent´³rec´³lit³ racket-event„´³tupleµ´³named³source´³embedded³any„„´³named³event´³embedded³any„„„„„„³ embeddedType€„„µ³transportAddress„´³schema·³version³ definitions·³Tcp´³rec´³lit³tcp„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³Unix´³rec´³lit³unix„´³tupleµ´³named³path´³atom³String„„„„„³Stdio´³rec´³lit³stdio„´³tupleµ„„„³ WebSocket´³rec´³lit³ws„´³tupleµ´³named³url´³atom³String„„„„„„³ embeddedType€„„µ³dataspacePatterns„´³schema·³version³ definitions·³DLit´³rec´³lit³lit„´³tupleµ´³named³value´³refµ„³AnyAtom„„„„„³DBind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³AnyAtom´³orµµ±bool´³atom³Boolean„„µ±float´³atom³Float„„µ±double´³atom³Double„„µ±int´³atom³ SignedInteger„„µ±string´³atom³String„„µ±bytes´³atom³
ByteString„„µ±symbol´³atom³Symbol„„µ±embedded´³embedded³any„„„„³Pattern´³orµµ±DDiscard´³refµ„³DDiscard„„µ±DBind´³refµ„³DBind„„µ±DLit´³refµ„³DLit„„µ± DCompound´³refµ„³ DCompound„„„„³DDiscard´³rec´³lit³_„´³tupleµ„„„³ DCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Pattern„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Pattern„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³secureChatProtocol„´³schema·³version³ definitions·³Join´³rec´³lit³
joinedUser„´³tupleµ´³named³uid´³refµ„³UserId„„´³named³handle´³embedded´³refµ„³Session„„„„„„³Says´³rec´³lit³says„´³tupleµ´³named³who´³refµ„³UserId„„´³named³what´³atom³String„„„„„³UserId´³atom³ SignedInteger„³Session´³orµµ± observeUsers´³rec´³lit³Observe„´³tupleµ´³lit³user„´³named³observer´³embedded´³refµ„³UserInfo„„„„„„„µ± observeSpeech´³rec´³lit³Observe„´³tupleµ´³lit³says„´³named³observer´³embedded´³refµ„³Says„„„„„„„µ± NickClaim´³refµ„³ NickClaim„„µ±Says´³refµ„³Says„„„„³UserInfo´³rec´³lit³user„´³tupleµ´³named³uid´³refµ„³UserId„„´³named³name´³atom³String„„„„„³ NickClaim´³rec´³lit³ claimNick„´³tupleµ´³named³uid´³refµ„³UserId„„´³named³name´³atom³String„„´³named³k´³embedded´³refµ„³NickClaimResponse„„„„„„³ NickConflict´³rec´³lit³ nickConflict„´³tupleµ„„„³NickClaimResponse´³orµµ±true´³lit<69>„„µ± NickConflict´³refµ„³ NickConflict„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³simpleChatProtocol„´³schema·³version³ definitions·³Says´³rec´³lit³Says„´³tupleµ´³named³who´³atom³String„„´³named³what´³atom³String„„„„„³Present´³rec´³lit³Present„´³tupleµ´³named³username´³atom³String„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„„„
TAttenuate„„µ±TRef´³refµ„³TRef„„µ±Lit´³refµ„³Lit„„µ± TCompound´³refµ„³ TCompound„„„„³ PCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Pattern„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Pattern„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„³ PEmbedded´³lit³Embedded„³ SturdyRef´³rec´³lit³ref„´³tupleµ´³named³
parameters´³refµ„³
Parameters„„„„„³ TCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Template„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Template„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Template„„„„„„„„„³
Parameters´³andµ´³dict·³oid´³named³oid³any„³sig´³named³sig´³atom³
ByteString„„„„´³named³caveats´³refµ„³ CaveatsField„„„„³
TAttenuate´³rec´³lit³ attenuate„´³tupleµ´³named³template´³refµ„³Template„„´³named³ attenuation´³seqof´³refµ„³Caveat„„„„„„³ CaveatsField´³orµµ±present´³dict·³caveats´³named³caveats´³seqof´³refµ„³Caveat„„„„„„µ±invalid´³dict·³caveats´³named³caveats³any„„„„µ±absent´³dict·„„„„„³SturdyStepType´³lit³ref„³SturdyStepDetail´³refµ„³
Parameters„³SturdyPathStepDetail´³refµ„³
Parameters„³SturdyDescriptionDetail´³dict·³key´³named³key´³atom³
ByteString„„³oid´³named³oid³any„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³worker„´³schema·³version°³ definitions·³Instance´³rec´³lit³Instance„´³tupleµ´³named³name´³atom³String„„´³named³argument³any„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³service„´³schema·³version°³ definitions·³State´³orµµ±started´³lit³started„„µ±ready´³lit³ready„„µ±failed´³lit³failed„„µ±complete´³lit³complete„„µ± userDefined³any„„„³
RunService´³rec´³lit³ run-service„´³tupleµ´³named³ serviceName³any„„„„³ ServiceState´³rec´³lit³ service-state„´³tupleµ´³named³ serviceName³any„´³named³state´³refµ„³State„„„„„³ ServiceObject´³rec´³lit³service-object„´³tupleµ´³named³ serviceName³any„´³named³object³any„„„„³RequireService´³rec´³lit³require-service„´³tupleµ´³named³ serviceName³any„„„„³RestartService´³rec´³lit³restart-service„´³tupleµ´³named³ serviceName³any„„„„³ServiceDependency´³rec´³lit³
depends-on„´³tupleµ´³named³depender³any„´³named³dependee´³refµ„³ ServiceState„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³protocol„´³schema·³version°³ definitions·³Nop´³lit€„³Oid´³atom³ SignedInteger„³Sync´³rec´³lit³S„´³tupleµ´³named³peer´³embedded´³lit<69>„„„„„„³Turn´³seqof´³refµ„³ TurnEvent„„³Error´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„´³named³detail³any„„„„³Event´³orµµ±Assert´³refµ„³Assert„„µ±Retract´³refµ„³Retract„„µ±Message´³refµ„³Message„„µ±Sync´³refµ„³Sync„„„„³Assert´³rec´³lit³A„´³tupleµ´³named³ assertion´³refµ„³ Assertion„„´³named³handle´³refµ„³Handle„„„„„³Handle´³atom³ SignedInteger„³Packet´³orµµ±Turn´³refµ„³Turn„„µ±Error´³refµ„³Error„„µ± Extension´³refµ„³ Extension„„µ±Nop´³refµ„³Nop„„„„³Message´³rec´³lit³M„´³tupleµ´³named³body´³refµ„³ Assertion„„„„„³Retract´³rec´³lit³R„´³tupleµ´³named³handle´³refµ„³Handle„„„„„³ Assertion³any³ Extension´³rec´³named³label³any„´³named³fields´³seqof³any„„„³ TurnEvent´³tupleµ´³named³oid´³refµ„³Oid„„´³named³event´³refµ„³Event„„„„„³ embeddedType€„„µ³ dataspace„´³schema·³version°³ definitions·³Observe´³rec´³lit³Observe„´³tupleµ´³named³pattern´³refµ³dataspacePatterns„³Pattern„„´³named³observer´³embedded³any„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³
gatekeeper„´³schema·³version°³ definitions·³Bind´³rec´³lit³bind„´³tupleµ´³named³ description´³refµ„³ Description„„´³named³target´³embedded³any„„´³named³observer´³refµ„³ BindObserver„„„„„³Step´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Bound´³orµµ±bound´³rec´³lit³bound„´³tupleµ´³named³pathStep´³refµ„³PathStep„„„„„„µ±Rejected´³refµ„³Rejected„„„„³Route´³rec´³lit³route„´³ tuplePrefixµ´³named³
transports´³seqof³any„„„´³named³ pathSteps´³seqof´³refµ„³PathStep„„„„„³Resolve´³rec´³lit³resolve„´³tupleµ´³named³step´³refµ„³Step„„´³named³observer´³embedded´³refµ„³Resolved„„„„„„³PathStep´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Rejected´³rec´³lit³rejected„´³tupleµ´³named³detail³any„„„„³Resolved´³orµµ±accepted´³rec´³lit³accepted„´³tupleµ´³named³responderSession´³embedded³any„„„„„„µ±Rejected´³refµ„³Rejected„„„„³ Description´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³ ResolvePath´³rec´³lit³ resolve-path„´³tupleµ´³named³route´³refµ„³Route„„´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„³ BindObserver´³orµµ±present´³embedded´³refµ„³Bound„„„µ±absent´³lit€„„„„³ForceDisconnect´³rec´³lit³force-disconnect„´³tupleµ„„„³ResolvedPathStep´³rec´³lit³ path-step„´³tupleµ´³named³origin´³embedded´³refµ„³Resolve„„„´³named³pathStep´³refµ„³PathStep„„´³named³resolved´³refµ„³Resolved„„„„„³TransportControl´³refµ„³ForceDisconnect„³TransportConnection´³rec´³lit³connect-transport„´³tupleµ´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³transportAddress„´³schema·³version°³ definitions·³Tcp´³rec´³lit³tcp„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³Unix´³rec´³lit³unix„´³tupleµ´³named³path´³atom³String„„„„„³Stdio´³rec´³lit³stdio„´³tupleµ„„„³ WebSocket´³rec´³lit³ws„´³tupleµ´³named³url´³atom³String„„„„„„³ embeddedType€„„µ³dataspacePatterns„´³schema·³version°³ definitions·³AnyAtom´³orµµ±bool´³atom³Boolean„„µ±double´³atom³Double„„µ±int´³atom³ SignedInteger„„µ±string´³atom³String„„µ±bytes´³atom³
ByteString„„µ±symbol´³atom³Symbol„„µ±embedded´³embedded³any„„„„³Pattern´³orµµ±discard´³rec´³lit³_„´³tupleµ„„„„µ±bind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value´³refµ„³AnyAtom„„„„„„µ±group´³rec´³lit³group„´³tupleµ´³named³type´³refµ„³ GroupType„„´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„³ GroupType´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„„„„„µ±arr´³rec´³lit³arr„´³tupleµ„„„„µ±dict´³rec´³lit³dict„´³tupleµ„„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„„„

View File

@ -1,4 +1,4 @@
version 1 .
embeddedType EntityRef.Cap .
Observe = <Observe @pattern dataspacePatterns.Pattern @observer #!any>.
Observe = <Observe @pattern dataspacePatterns.Pattern @observer #:any>.

View File

@ -1,23 +1,30 @@
version 1 .
embeddedType EntityRef.Cap .
; Dataspace patterns: a sublanguage of attenuation patterns.
Pattern = DDiscard / DBind / DLit / DCompound .
# Dataspace patterns: *almost* a sublanguage of attenuation patterns.
#
# One key difference is that Dataspace patterns are extensible, in that
# they ignore fields not mentioned in group patterns.
DDiscard = <_>.
DBind = <bind @pattern Pattern>.
DLit = <lit @value AnyAtom>.
DCompound = <rec @label any @fields [Pattern ...]>
/ <arr @items [Pattern ...]>
/ <dict @entries { any: Pattern ...:... }> .
Pattern =
/ @discard <_>
/ <bind @pattern Pattern>
/ <lit @value AnyAtom>
/ <group @type GroupType @entries { any: Pattern ...:... }>
.
GroupType =
/ <rec @label any>
/ <arr>
/ <dict>
.
AnyAtom =
/ @bool bool
/ @float float
/ @double double
/ @int int
/ @string string
/ @bytes bytes
/ @symbol symbol
/ @embedded #!any
/ @embedded #:any
.

View File

@ -1,5 +1,87 @@
version 1 .
embeddedType EntityRef.Cap .
Resolve = <resolve @sturdyref sturdy.SturdyRef @observer #!#!any>.
Bind = <bind @oid any @key bytes @target #!any>.
# ---------------------------------------------------------------------------
# Protocol at *gatekeeper* entities
# Assertion. Gatekeeper will attempt to resolve `step`, responding with a `Resolved` to
# `observer`.
Resolve = <resolve @step Step @observer #:Resolved> .
Resolved = <accepted @responderSession #:any> / Rejected .
Step = <<rec> @stepType symbol [@detail any]> .
# ---------------------------------------------------------------------------
# Protocol at dataspaces *associated* with gatekeeper entities
# ## Handling `Resolve` requests
#
# When the gatekeeper entity receives a `Resolve` assertion (call it R1), it
#
# 1. asserts a `Resolve` (call it R2) into its associated dataspace that
# is the same as R1 except it has a different `observer`; and
#
# 2. observes a `Bind` with `description` matching the `step` of R1/R2
# according to `stepType` (e.g. treatment of SturdyStepType is not the
# same as treatment of NoiseStepType).
#
# Normally, an appropriate `Bind` is expected to exist. If the gatekeeper
# sees the `Bind` first, it takes the `target` from it and does whatever
# `stepType` mandates before replying to R1's observer.
#
# However, if a `Resolved` is asserted to R2's observer before a `Bind`
# appears, that resolution is relayed on to R1's observer directly, be it
# positive or negative, and the gatekeeper stops waiting for a `Bind`.
#
# This way, entities can keep an eye out for `Resolve` requests that will
# never complete, and answer `Rejected` to them even when no matching
# `Bind` exists. Entities could also use `Resolve` requests to synthesize a
# `Bind` in a "just-in-time" fashion.
#
# ## General treatment of `Bind` assertions
#
# When the gatekeeper sees a `Bind`, independently of any potential
# `Resolve` requests, it computes an appropriate PathStep from
# `description` pointing at `target`, and responds with a `Bound` to
# `observer` (if supplied).
#
Bind = <bind @description Description @target #:any @observer BindObserver> .
Description = <<rec> @stepType symbol [@detail any]> .
BindObserver = @present #:Bound / @absent #f .
Bound = <bound @pathStep PathStep> / Rejected .
# ---------------------------------------------------------------------------
# Protocol at client-side dataspaces, for resolution utilities
# Assertion. In response to observation of this with appropriate captures/wildcards in `addr`
# and `resolved`, respondent will follow `route.pathSteps` starting from one of the
# `route.transports`, asserting `ResolvePath` with the final `Resolved` as well as the selected
# transport `addr` and a `control` for it.
ResolvePath = <resolve-path @route Route @addr any @control #:TransportControl @resolved Resolved> .
TransportConnection = <connect-transport @addr any @control #:TransportControl @resolved Resolved> .
ResolvedPathStep = <path-step @origin #:Resolve @pathStep PathStep @resolved Resolved> .
PathStep = <<rec> @stepType symbol [@detail any]> .
# A `Route` describes a network path that can be followed to reach some target entity.
#
# It starts with a set of zero or more possible non-Syndicate `transports`. These could be
# `transportAddress.Tcp` values or similar. They are just suggestions; it's quite possible the
# endpoint is reachable by some means not listed. The network outside Syndicate is, after all,
# pretty diverse! In particular, *zero* `transports` may be provided, in which case some
# out-of-band means has to be used to make that first connection.
#
# The `transports` give instructions for contacting the first entity in the `Route` path. Often
# this will be a `gatekeeper`, or a `noise` protocol endpoint, or both. Occasionally, it may
# even be the desired target entity. Subsequent `pathSteps` describe how to proceed from the
# initial entity to the target.
#
# (`transports` should by rights be a set, not a sequence, but that opens up a Can Of Worms
# regarding dataspace patterns including literal sets that I can't deal with right now.)
Route = <route @transports [any ...] @pathSteps PathStep ...> .
TransportControl = ForceDisconnect .
ForceDisconnect = <force-disconnect> .
# ---------------------------------------------------------------------------
Rejected = <rejected @detail any> .

View File

@ -0,0 +1,62 @@
version 1 .
# Assertion in driver DS
# Causes creation of server and route
HttpBinding = <http-bind @host HostPattern @port int @method MethodPattern @path PathPattern @handler #:HttpRequest> .
# Assertion in driver DS
# Describes active server and route
HttpService = <http-service @host HostPattern @port int @method MethodPattern @path PathPattern> .
# Assertion in driver DS
# Describes active listener
HttpListener = <http-listener @port int> .
HostPattern = @host string / @any #f .
PathPattern = [PathPatternElement ...] .
PathPatternElement = @label string / @wildcard =_ / @rest =... .
MethodPattern = @any #f / @specific @"Lowercase" symbol .
# Assertion in driver DS
HttpRequest = <http-request
@sequenceNumber int
@host RequestHost
@port int
@method @"Lowercase" symbol
@path [string ...]
@headers Headers
@query {symbol: [QueryValue ...] ...:...}
@body RequestBody> .
Headers = {@"Lowercase" symbol: string ...:...} .
QueryValue = @string string / <file @filename string @headers Headers @body bytes> .
RequestBody = @absent #f / @present bytes .
RequestHost = @absent #f / @present string .
# Assertion to handler entity
HttpContext = <request @req HttpRequest @res #:HttpResponse> .
# HttpResponse protocol. Delivered to the `res` ref in `HttpContext`.
#
# (status | header)* . chunk* . done
#
# Done triggers completion of the response and retraction of the frame by the peer. If the
# HttpBinding responsible for the request is withdrawn mid-way through a response (i.e. when
# chunked transfer is used and at least one chunk has been sent) the request is abruptly
# closed; if it is withdrawn at any other moment in the lifetime of the request, a 500 Internal
# Server Error is send to the client.
#
@<TODO "trailers?">
HttpResponse =
# Messages.
/ <status @code int @message string>
/ <header @name symbol @value string>
/ <chunk @chunk Chunk>
/ <done @chunk Chunk>
.
Chunk = @string string / @bytes bytes .
# e.g. text/plain, text/html, application/json
MimeType = symbol .

View File

@ -0,0 +1,83 @@
version 1 .
embeddedType EntityRef.Cap .
# https://noiseprotocol.org/
# ---------------------------------------------------------------------------
# Binding and connection
NoiseStepType = =noise .
# In a gatekeeper.Step, use ServiceSelector as detail.
NoiseStepDetail = ServiceSelector .
# In a gatekeeper.PathStep, use a NoiseSpec as detail.
NoisePathStepDetail = NoiseSpec .
# In a gatekeeper.Description, use a NoiseServiceSpec as detail.
NoiseDescriptionDetail = NoiseServiceSpec .
# ---------------------------------------------------------------------------
# Specification of target and bind addresses
ServiceSelector = any .
NoiseSpec = {
# The `serviceSelector` to use in a `NoiseStep` for `gatekeeper.Resolve`.
service: ServiceSelector,
# The responder's static public key. If not required (uncommon!), supply the empty ByteString.
key: bytes,
}
& @protocol NoiseProtocol
& @preSharedKeys NoisePreSharedKeys
.
NoiseServiceSpec = @base NoiseSpec & @secretKey SecretKeyField .
SecretKeyField = @present { secretKey: bytes } / @invalid { secretKey: any } / @absent {} .
# If absent, a default of DefaultProtocol is used. Most services will speak the default.
NoiseProtocol = @present { protocol: string } / @invalid { protocol: any } / @absent {} .
DefaultProtocol = "Noise_NK_25519_ChaChaPoly_BLAKE2s" .
# If present, Noise pre-shared-keys (PSKs) are drawn from the sequence as required; if the
# sequence is exhausted or not supplied, an all-zeros key is used each time a PSK is needed.
NoisePreSharedKeys = @present { preSharedKeys: [bytes ...] } / @invalid { preSharedKeys: any } / @absent {} .
# ---------------------------------------------------------------------------
# Handshaking and running a session
# 1. initiator asserts <resolve <noise ServiceSelector> #:A> at Gatekeeper
# 2. gatekeeper asserts <accepted #:B> at #:A
# 3. initiator asserts <initiator #:C> at #:B and then sends `Packet`s to #:B
# 4. responder sends `Packet`s to #:C
#
# Sessions begin with introduction of initiator (#:C) and responder (#:B) to each other, and
# then proceed by sending `Packet`s (from #:C) to #:B and (from #:B) to #:C according to
# the Noise protocol definition. Each `Packet` represents a complete logical unit of
# communication; for example, a complete Turn when layering the Syndicate protocol over Noise.
# Note well the restriction on Noise messages: no individual complete packet or packet fragment
# may exceed 65535 bytes (N.B. not 65536!). When `fragmented`, each portion of a `Packet` is a
# complete Noise "transport message"; when `complete`, the whole thing is likewise a complete
# "transport message".
#
# Retraction of the `Initiator` ends the session from the initiator-side; retraction of the
# `<accepted ...>` assertion ends the session from the responder-side.
SessionItem = Initiator / Packet .
# Assertion
Initiator = <initiator @initiatorSession #:Packet> .
# Message
Packet = @complete bytes / @fragmented [bytes ...] .
# When layering Syndicate protocol over noise,
#
# - the canonical encoding of the serviceSelector is the prologue
# - protocol.Packets MUST be encoded using the machine-oriented Preserves syntax
# - zero or more Turns are permitted per noise.Packet
# - each Turn must fit inside a single noise.Packet (fragment if needed)
# - payloads inside a noise.Packet may be padded at the end with byte 0x80 (128), which
# encodes `#f` in the machine-oriented Preserves syntax.
#
# In summary, each noise.Packet, once (reassembled and) decrypted, will be a sequence of zero
# or more machine-encoded protocol.Packets, followed by zero or more 0x80 bytes.
.

View File

@ -1,6 +1,9 @@
version 1 .
Packet = Turn / Error .
Packet = Turn / Error / Extension / Nop .
Extension = <<rec> @label any @fields [any ...]> .
Nop = #f .
Error = <error @message string @detail any>.
@ -11,7 +14,7 @@ Oid = int .
Turn = [TurnEvent ...].
TurnEvent = [@oid Oid @event Event].
Assert = <assert @assertion Assertion @handle Handle>.
Retract = <retract @handle Handle>.
Message = <message @body Assertion>.
Sync = <sync @peer #!#t>.
Assert = <A @assertion Assertion @handle Handle>.
Retract = <R @handle Handle>.
Message = <M @body Assertion>.
Sync = <S @peer #:#t>.

View File

@ -1,3 +0,0 @@
version 1 .
RacketEvent = <racket-event @source #!any @event #!any>.

View File

@ -1,21 +0,0 @@
version 1 .
embeddedType EntityRef.Cap .
UserId = int .
Join = <joinedUser @uid UserId @handle #!Session>.
Session = @observeUsers <Observe =user @observer #!UserInfo>
/ @observeSpeech <Observe =says @observer #!Says>
/ NickClaim
/ Says
.
NickClaim = <claimNick @uid UserId @name string @k #!NickClaimResponse>.
NickClaimResponse = #t / NickConflict .
UserInfo = <user @uid UserId @name string>.
Says = <says @who UserId @what string>.
NickConflict = <nickConflict>.

View File

@ -1,51 +1,51 @@
version 1 .
embeddedType EntityRef.Cap .
; Asserts that a service should begin (and stay) running after waiting
; for its dependencies and considering reverse-dependencies, blocks,
; and so on.
# Asserts that a service should begin (and stay) running after waiting
# for its dependencies and considering reverse-dependencies, blocks,
# and so on.
RequireService = <require-service @serviceName any>.
; Asserts that a service should begin (and stay) running RIGHT NOW,
; without considering its dependencies.
# Asserts that a service should begin (and stay) running RIGHT NOW,
# without considering its dependencies.
RunService = <run-service @serviceName any>.
; Asserts one or more current states of service `serviceName`. The
; overall state of the service is the union of asserted `state`s.
;
; Only a few combinations make sense:
; - `started`
; - `started` + `ready`
; - `failed`
; - `complete`
;
# Asserts one or more current states of service `serviceName`. The
# overall state of the service is the union of asserted `state`s.
#
# Only a few combinations make sense:
# - `started`
# - `started` + `ready`
# - `failed`
# - `complete`
#
ServiceState = <service-state @serviceName any @state State>.
; A running service publishes zero or more of these. The details of
; the object vary by service.
;
# A running service publishes zero or more of these. The details of
# the object vary by service.
#
ServiceObject = <service-object @serviceName any @object any>.
; Possible service states.
# Possible service states.
State =
/ ; The service has begun its startup routine, and may or may not be
; ready to take requests from other parties.
/ # The service has begun its startup routine, and may or may not be
# ready to take requests from other parties.
=started
/ ; The service is ready to take requests from other parties.
; (This state is special in that it is asserted *in addition* to `started`.)
/ # The service is ready to take requests from other parties.
# (This state is special in that it is asserted *in addition* to `started`.)
=ready
/ ; The service has failed.
/ # The service has failed.
=failed
/ ; The service has completed execution.
/ # The service has completed execution.
=complete
/ # Extension or user-defined state
@userDefined any
.
; Asserts that, when `depender` is `require-service`d, it should not
; be started until `dependee` has been asserted.
# Asserts that, when `depender` is `require-service`d, it should not be started until
# `dependee` has been asserted, and also that `dependee`'s `serviceName` should be
# `require-service`d.
ServiceDependency = <depends-on @depender any @dependee ServiceState>.
; Asserts that the service is a "core" service. If *not* specified for
; a service X, where X is not `<milestone Y>` for some Y, the system
; acts as if `<depends-on X <service-state <milestone core> ready>>`
; were asserted.
CoreService = <core-service @serviceName any>.
# Message. Triggers a service restart.
RestartService = <restart-service @serviceName any>.

View File

@ -0,0 +1,31 @@
version 1 .
# A "standard" route is
#
# - a collection of websocket urls, for transport.
# - a noise tunnel, for server authentication, confidentiality and integrity.
# - a macaroon, for authorization.
#
# Making these choices allows a compact representation. Encoding a binary-syntax representation
# of a standard route using base64 produces a somewhat-convenient blob of text representing
# access to a network object that users can cut and paste.
#
# A `stdenv.StandardRoute.standard` can be rewritten to a `gatekeeper.Route` like this (with
# `$caveats`, if any, added as appropriate):
#
# <route $transports <noise { service: $service key: $key }> <ref { sig: $sig oid: $oid }>>
#
StandardRoute =
/ @standard [@transports [StandardTransport ...]
@key bytes
@service any
@sig bytes
@oid any
@caveats sturdy.Caveat ...]
/ @general gatekeeper.Route
.
StandardTransport =
/ @wsUrl string
/ @other any
.

View File

@ -1,38 +1,38 @@
version 1 .
embeddedType EntityRef.Cap .
; Assertion:
StreamConnection = <stream-connection @source #!Source @sink #!Sink @spec any>.
# Assertion:
StreamConnection = <stream-connection @source #:Source @sink #:Sink @spec any>.
; Assertions:
# Assertions:
StreamListenerReady = <stream-listener-ready @spec any>.
StreamListenerError = <stream-listener-error @spec any @message string>.
; Assertion:
# Assertion:
StreamError = <error @message string>.
Source =
; Assertions:
/ <sink @controller #!Sink>
# Assertions:
/ <sink @controller #:Sink>
/ StreamError
; Messages:
# Messages:
/ <credit @amount CreditAmount @mode Mode>
.
Sink =
; Assertions:
/ <source @controller #!Source>
# Assertions:
/ <source @controller #:Source>
/ StreamError
; Messages:
# Messages:
/ <data @payload any @mode Mode>
/ <eof>
.
; Value:
# Value:
CreditAmount = @count int / @unbounded =unbounded .
; Value:
# Value:
Mode = =bytes / @lines LineMode / <packet @size int> / <object @description any>.
LineMode = =lf / =crlf .

View File

@ -1,30 +1,57 @@
version 1 .
embeddedType EntityRef.Cap .
; Each Attenuation is a stage. The sequence of Attenuations is run RIGHT-TO-LEFT.
; That is, the newest Attenuations are at the right.
SturdyRef = <ref @oid any @caveatChain [Attenuation ...] @sig bytes>.
# ---------------------------------------------------------------------------
# Binding and connection
; An individual Attenuation is run RIGHT-TO-LEFT.
; That is, the newest Caveats are at the right.
Attenuation = [Caveat ...].
SturdyStepType = =ref .
; embodies 1st-party caveats over assertion structure, but nothing else
; can add 3rd-party caveats and richer predicates later
Caveat = Rewrite / Alts .
Rewrite = <rewrite @pattern Pattern @template Template>.
# In a gatekeeper.Step or gatekeeper.PathStep, use Parameters as detail.
SturdyStepDetail = Parameters .
SturdyPathStepDetail = Parameters .
# In a gatekeeper.Description, use the following detail.
SturdyDescriptionDetail = {
oid: any,
key: bytes,
} .
# ---------------------------------------------------------------------------
# Macaroons
# The sequence of Caveats is run RIGHT-TO-LEFT.
# That is, the newest Caveats are at the right.
#
# Let f(k,d) = HMAC-BLAKE2s-256(k,d)[0..16),
# e = canonical machine-oriented serialization of some preserves value, and
# k = the original secret key for the ref.
#
# The `sig` is then f(f(f(f(k, e(oid)), ...), e(Caveat)), ...).
#
SturdyRef = <ref @parameters Parameters> .
Parameters = {
oid: any,
sig: bytes,
} & @caveats CaveatsField .
CaveatsField = @present { caveats: [Caveat ...] } / @invalid { caveats: any } / @absent {} .
# embodies 1st-party caveats over assertion structure, but nothing else
# can add 3rd-party caveats and richer predicates later
Caveat = Rewrite / Alts / Reject / @unknown any .
Rewrite = <rewrite @pattern Pattern @template Template> .
Reject = <reject @pattern Pattern> .
Alts = <or @alternatives [Rewrite ...]>.
Oid = int .
WireRef = @mine [0 @oid Oid] / @yours [1 @oid Oid @attenuation Caveat ...].
;---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
Lit = <lit @value any>.
Pattern = PDiscard / PAtom / PEmbedded / PBind / PAnd / PNot / Lit / PCompound .
PDiscard = <_>.
PAtom = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
PAtom = =Boolean / =Double / =SignedInteger / =String / =ByteString / =Symbol .
PEmbedded = =Embedded .
PBind = <bind @pattern Pattern>.
PAnd = <and @patterns [Pattern ...]>.
@ -35,7 +62,7 @@ PCompound =
/ @dict <dict @entries { any: Pattern ...:... }> .
Template = TAttenuate / TRef / Lit / TCompound .
TAttenuate = <attenuate @template Template @attenuation Attenuation>.
TAttenuate = <attenuate @template Template @attenuation [Caveat ...]>.
TRef = <ref @binding int>.
TCompound =
/ @rec <rec @label any @fields [Template ...]>

View File

@ -4,4 +4,4 @@ embeddedType EntityRef.Cap .
TcpRemote = <tcp-remote @host string @port int>.
TcpLocal = <tcp-local @host string @port int>.
TcpPeerInfo = <tcp-peer @handle #!any @local TcpLocal @remote TcpRemote>.
TcpPeerInfo = <tcp-peer @handle #:any @local TcpLocal @remote TcpRemote>.

View File

@ -1,7 +1,7 @@
version 1 .
SetTimer = <set-timer @label any @msecs double @kind TimerKind>.
TimerExpired = <timer-expired @label any @msecs double>.
SetTimer = <set-timer @label any @seconds double @kind TimerKind>.
TimerExpired = <timer-expired @label any @seconds double>.
TimerKind = =relative / =absolute / =clear .
LaterThan = <later-than @msecs double>.
LaterThan = <later-than @seconds double>.

View File

@ -0,0 +1,96 @@
version 1 .
embeddedType EntityRef.Cap .
TraceEntry = <trace
@timestamp @"seconds since Unix epoch" double
@actor ActorId
@item ActorActivation> .
ActorActivation =
/ <start @actorName Name>
/ @turn TurnDescription
/ <stop @status ExitStatus>
.
Name =
/ <anonymous>
/ <named @name any>
.
ActorId = any .
FacetId = any .
Oid = any .
TaskId = any .
TurnId = any .
ExitStatus = =ok / protocol.Error .
# Trace information associated with a turn.
TurnDescription = <turn @id TurnId @cause TurnCause @actions [ActionDescription ...]> .
# The cause of a turn.
TurnCause =
/ @turn <caused-by @id TurnId>
/ <cleanup>
/ @linkedTaskRelease <linked-task-release @id TaskId @reason LinkedTaskReleaseReason>
/ @periodicActivation <periodic-activation @"`period` is in seconds" @period double>
/ <delay @causingTurn TurnId @"`amount` is in seconds" @amount double>
/ <external @description any>
.
LinkedTaskReleaseReason = =cancelled / =normal .
# An actual event carried within a turn.
TurnEvent =
/ <assert @assertion AssertionDescription @handle protocol.Handle>
/ <retract @handle protocol.Handle>
/ <message @body AssertionDescription>
/ <sync @peer Target>
/ # A souped-up, disguised, special-purpose `retract` event.
@breakLink <break-link @source ActorId @handle protocol.Handle>
.
TargetedTurnEvent = <event @target Target @detail TurnEvent> .
# An action taken during a turn.
ActionDescription =
/ # The active party is processing a new `event` for `target` from the received Turn.
<dequeue @event TargetedTurnEvent>
/ # The active party has queued a new `event` to be processed later by `target`.
<enqueue @event TargetedTurnEvent>
/ # The active party is processing an internally-queued event for one of its own entities.
@dequeueInternal <dequeue-internal @event TargetedTurnEvent>
/ # The active party has scheduled an internally-queued event for one of its own entities.
@enqueueInternal <enqueue-internal @event TargetedTurnEvent>
/ <spawn @link bool @id ActorId>
/ <link
@parentActor ActorId
@childToParent protocol.Handle
@childActor ActorId
@parentToChild protocol.Handle>
/ @facetStart <facet-start @path [FacetId ...]>
/ @facetStop <facet-stop @path [FacetId ...] @reason FacetStopReason>
/ @linkedTaskStart <linked-task-start @taskName Name @id TaskId>
.
# An assertion or the body of a message: either a Preserves value, or
# some opaque system-internal value, represented according to the
# system concerned.
AssertionDescription =
/ <value @value any>
/ <opaque @description any>
.
FacetStopReason =
/ @explicitAction =explicit-action
/ =inert
/ @parentStopping =parent-stopping
/ @actorStopping =actor-stopping
.
Target = <entity @actor ActorId @facet FacetId @oid Oid> .
# For the future: consider including information about `protocol`-level `Turn`s etc sent to
# peers over e.g. Websockets or TCP/IP, allowing cross-correlation of traces from different
# processes and implementations with each other to form a large overall picture.
.

View File

@ -1,7 +1,5 @@
import sys
import asyncio
import websockets
import logging
from preserves import Embedded, stringify
from preserves.fold import map_embeddeds
@ -73,6 +71,7 @@ class TunnelRelay:
publish_oid = 0,
on_connected = None,
on_disconnected = None,
connection_timeout = None,
):
self.facet = turn.active_facet()
self.facet.on_stop(self._shutdown)
@ -81,9 +80,10 @@ class TunnelRelay:
self.gatekeeper_oid = gatekeeper_oid
self.publish_service = publish_service
self.publish_oid = publish_oid
self.connection_timeout = connection_timeout
self._reset()
self.facet.linked_task(
lambda facet: self._reconnecting_main(asyncio.get_running_loop(),
lambda facet: self._reconnecting_main(facet.actor._system,
on_connected = on_connected,
on_disconnected = on_disconnected))
@ -187,9 +187,12 @@ class TunnelRelay:
def _handle_event(self, v):
packet = protocol.Packet.decode(v)
# self.facet.log.info('IN: %r', packet)
variant = packet.VARIANT.name
if variant == 'Turn': self._handle_turn_events(packet.value.value)
elif variant == 'Error': self._on_error(packet.value.message, packet.value.detail)
elif variant == 'Extension': pass
elif variant == 'Nop': pass
def _on_error(self, message, detail):
self.facet.log.error('Error from server: %r (detail: %r)', message, detail)
@ -243,8 +246,9 @@ class TunnelRelay:
def flush_pending():
packet = protocol.Packet.Turn(protocol.Turn(self.pending_turn))
self.pending_turn = []
# self.facet.log.info('OUT: %r', packet)
self._send_bytes(encode(packet))
actor.queue_task(lambda: turn.run(self.facet, flush_pending))
self.facet.actor._system.queue_task(lambda: turn.run(self.facet, flush_pending))
self.pending_turn.append(protocol.TurnEvent(protocol.Oid(remote_oid), turn_event))
def _send_bytes(self, bs):
@ -253,10 +257,10 @@ class TunnelRelay:
def _disconnect(self):
raise Exception('subclassresponsibility')
async def _reconnecting_main(self, loop, on_connected=None, on_disconnected=None):
async def _reconnecting_main(self, system, on_connected=None, on_disconnected=None):
should_run = True
while should_run and self.facet.alive:
did_connect = await self.main(loop, on_connected=(on_connected or _default_on_connected))
did_connect = await self.main(system, on_connected=(on_connected or _default_on_connected))
should_run = await (on_disconnected or _default_on_disconnected)(self, did_connect)
@staticmethod
@ -264,11 +268,14 @@ class TunnelRelay:
return transport.connection_from_str(conn_str, **kwargs)
# decorator
def connect(conn_str, cap, **kwargs):
def connect(conn_str, cap = None, **kwargs):
def prepare_resolution_handler(handler):
@During().add_handler
def handle_gatekeeper(gk):
gatekeeper.resolve(gk.embeddedValue, cap)(handler)
if cap is None:
handler(gk.embeddedValue)
else:
gatekeeper.resolve(gk.embeddedValue, cap)(handler)
return transport.connection_from_str(
conn_str,
gatekeeper_peer = turn.ref(handle_gatekeeper),
@ -337,10 +344,6 @@ class _StreamTunnelRelay(TunnelRelay, asyncio.Protocol):
def connection_lost(self, exc):
self._on_disconnected()
def connection_made(self, transport):
self.transport = transport
self._on_connected()
def data_received(self, chunk):
self.decoder.extend(chunk)
while True:
@ -361,74 +364,88 @@ class _StreamTunnelRelay(TunnelRelay, asyncio.Protocol):
pass
self.stop_signal.get_loop().call_soon_threadsafe(set_stop_signal)
async def _create_connection(self, loop):
async def _create_connection(self, system):
raise Exception('subclassresponsibility')
async def main(self, loop, on_connected=None):
async def main(self, system, on_connected=None):
if self.transport is not None:
raise Exception('Cannot run connection twice!')
self.decoder = Decoder(decode_embedded = sturdy.WireRef.decode)
self.stop_signal = loop.create_future()
self.stop_signal = system.loop.create_future()
try:
_transport, _protocol = await self._create_connection(loop)
except OSError as e:
log.error('%s: Could not connect to server: %s' % (self.__class__.__qualname__, e))
return False
try:
transport, _protocol = await asyncio.wait_for(
self._create_connection(system), timeout=self.connection_timeout)
except asyncio.TimeoutError:
self.facet.log.error(
'%s: Timeout connecting to server' % (self.__class__.__qualname__,))
return False
except OSError as e:
self.facet.log.error(
'%s: Could not connect to server: %s' % (self.__class__.__qualname__, e))
return False
try:
self.transport = transport
self._on_connected()
if on_connected: await on_connected(self)
await self.stop_signal
return True
finally:
self.transport.close()
if self.transport:
self.transport.close()
self.transport = None
self.stop_signal = None
self.decoder = None
@transport.address(transportAddress.Tcp)
class TcpTunnelRelay(_StreamTunnelRelay):
async def _create_connection(self, loop):
return await loop.create_connection(lambda: self, self.address.host, self.address.port)
async def _create_connection(self, system):
return await system.loop.create_connection(lambda: self, self.address.host, self.address.port)
@transport.address(transportAddress.Unix)
class UnixSocketTunnelRelay(_StreamTunnelRelay):
async def _create_connection(self, loop):
return await loop.create_unix_connection(lambda: self, self.address.path)
async def _create_connection(self, system):
return await system.loop.create_unix_connection(lambda: self, self.address.path)
@transport.address(transportAddress.WebSocket)
class WebsocketTunnelRelay(TunnelRelay):
def __init__(self, address, **kwargs):
super().__init__(address, **kwargs)
self.loop = None
self.system = None
self.ws = None
def _send_bytes(self, bs):
if self.loop:
if self.system:
def _do_send():
if self.ws:
self.loop.create_task(self.ws.send(bs))
self.loop.call_soon_threadsafe(_do_send)
self.system.queue_task(lambda: self.ws.send(bs))
self.system.loop.call_soon_threadsafe(_do_send)
def _disconnect(self):
if self.loop:
if self.system:
def _do_disconnect():
if self.ws:
self.loop.create_task(self.ws.close())
self.loop.call_soon_threadsafe(_do_disconnect)
self.system.queue_task(lambda: self.ws.close())
self.system.loop.call_soon_threadsafe(_do_disconnect)
def __connection_error(self, e):
self.facet.log.error('Could not connect to server: %s' % (e,))
return False
async def main(self, loop, on_connected=None):
async def main(self, system, on_connected=None):
import websockets
if self.ws is not None:
raise Exception('Cannot run connection twice!')
self.loop = loop
self.system = system
try:
self.ws = await websockets.connect(self.address.url)
self.ws = await websockets.connect(
self.address.url, open_timeout=self.connection_timeout)
except asyncio.TimeoutError:
return self.__connection_error('timeout')
except OSError as e:
return self.__connection_error(e)
except websockets.exceptions.InvalidHandshake as e:
@ -447,7 +464,7 @@ class WebsocketTunnelRelay(TunnelRelay):
if self.ws:
await self.ws.close()
self.loop = None
self.system = None
self.ws = None
return True
@ -459,8 +476,8 @@ class PipeTunnelRelay(_StreamTunnelRelay):
self.output_fileobj = output_fileobj
self.reader = asyncio.StreamReader()
async def _create_connection(self, loop):
return await loop.connect_read_pipe(lambda: self, self.input_fileobj)
async def _create_connection(self, system):
return await system.loop.connect_read_pipe(lambda: self, self.input_fileobj)
def _send_bytes(self, bs):
self.output_fileobj.buffer.write(bs)
@ -471,5 +488,4 @@ def run_stdio_service(entity):
# decorator
def service(**kwargs):
return lambda entity: \
actor.start_actor_system(lambda: run_stdio_service(entity), **kwargs)
return lambda entity: actor.run_system(**kwargs)(lambda: run_stdio_service(entity))

View File

@ -1,32 +0,0 @@
from .actor import Turn
def __setup():
from .actor import _active
from types import FunctionType
import sys
mod = sys.modules[__name__]
def install_definition(name, definition):
def handler(*args, **kwargs):
return definition(_active.turn, *args, **kwargs)
setattr(mod, name, handler)
for (name, definition) in Turn.__dict__.items():
if name[0] == '_':
continue
elif type(definition) == FunctionType:
install_definition(name, definition)
else:
pass
__setup()
def run(facet, action):
Turn.run(facet, action)
def external(facet, action, loop=None):
Turn.external(facet, action, loop=loop)
def active_facet():
return Turn.active._facet