Solo5 support
This commit is contained in:
parent
2aee79662e
commit
7c72ea5732
|
@ -1,2 +1,5 @@
|
||||||
include depends.tup
|
include depends.tup
|
||||||
NIM_GROUPS += $(TUP_CWD)/<lock>
|
NIM_GROUPS += $(TUP_CWD)/<lock>
|
||||||
|
NIM_FLAGS += --path:$(TUP_CWD)/../cps
|
||||||
|
NIM_FLAGS += --path:$(TUP_CWD)/../solo5_dispatcher/pkg
|
||||||
|
NIM_FLAGS += --path:$(TUP_CWD)/../taps/src
|
||||||
|
|
107
lock.json
107
lock.json
|
@ -16,11 +16,33 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
"cps"
|
"cps"
|
||||||
],
|
],
|
||||||
"path": "/nix/store/452hfhasrn3gl6vijfmzs69djl099j0j-source",
|
"path": "/nix/store/8gbhwni0akqskdb3qhn5nfgv6gkdz0vz-source",
|
||||||
"rev": "b7c179f172e3a256a482a9daee3c0815ea423206",
|
"rev": "c90530ac57f98a842b7be969115c6ef08bdcc564",
|
||||||
"sha256": "1sn9s7iv83sw1jl5jgi2h7b0xpgsn13f9icp5124jvbp0qkxskx2",
|
"sha256": "0h8ghs2fqg68j3jdcg7grnxssmllmgg99kym2w0a3vlwca1zvr62",
|
||||||
"srcDir": "",
|
"srcDir": "",
|
||||||
"url": "https://github.com/nim-works/cps/archive/b7c179f172e3a256a482a9daee3c0815ea423206.tar.gz"
|
"url": "https://github.com/ehmry/cps/archive/c90530ac57f98a842b7be969115c6ef08bdcc564.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"getdns"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/x9xmn7w4k6jg8nv5bnx148ibhnsfh362-source",
|
||||||
|
"rev": "c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6",
|
||||||
|
"sha256": "1sbgx2x51szr22i72n7c8jglnfmr8m7y7ga0v85d58fwadiv7g6b",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://git.sr.ht/~ehmry/getdns-nim/archive/c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"getdns"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/x9xmn7w4k6jg8nv5bnx148ibhnsfh362-source",
|
||||||
|
"rev": "c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6",
|
||||||
|
"sha256": "1sbgx2x51szr22i72n7c8jglnfmr8m7y7ga0v85d58fwadiv7g6b",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://git.sr.ht/~ehmry/getdns-nim/archive/c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6.tar.gz"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "fetchzip",
|
"method": "fetchzip",
|
||||||
|
@ -38,22 +60,22 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
"nimcrypto"
|
"nimcrypto"
|
||||||
],
|
],
|
||||||
"path": "/nix/store/jwz8pqbv6rsm8w4fjzdb37r0wzjn5hv0-source",
|
"path": "/nix/store/fkrcpp8lzj2yi21na79xm63xk0ggnqsp-source",
|
||||||
"rev": "d58da671799c69c0b3208b96c154e13c8b1a9e90",
|
"rev": "f147d30c69bc1c9bcf0e37f7699bcf0fbaab97b5",
|
||||||
"sha256": "12dm0gsy10ppga7zf7hpf4adaqjrd9b740n2w926xyazq1njf6k9",
|
"sha256": "1h3dzdbc9kacwpi10mj73yjglvn7kbizj1x8qc9099ax091cj5xn",
|
||||||
"srcDir": "",
|
"srcDir": "",
|
||||||
"url": "https://github.com/cheatfate/nimcrypto/archive/d58da671799c69c0b3208b96c154e13c8b1a9e90.tar.gz"
|
"url": "https://github.com/cheatfate/nimcrypto/archive/f147d30c69bc1c9bcf0e37f7699bcf0fbaab97b5.tar.gz"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "fetchzip",
|
"method": "fetchzip",
|
||||||
"packages": [
|
"packages": [
|
||||||
"npeg"
|
"npeg"
|
||||||
],
|
],
|
||||||
"path": "/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source",
|
"path": "/nix/store/xpn694ibgipj8xak3j4bky6b3k0vp7hh-source",
|
||||||
"rev": "26d62fdc40feb84c6533956dc11d5ee9ea9b6c09",
|
"rev": "ec0cc6e64ea4c62d2aa382b176a4838474238f8d",
|
||||||
"sha256": "0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh",
|
"sha256": "1fi9ls3xl20bmv1ikillxywl96i9al6zmmxrbffx448gbrxs86kg",
|
||||||
"srcDir": "src",
|
"srcDir": "src",
|
||||||
"url": "https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"
|
"url": "https://github.com/zevv/npeg/archive/ec0cc6e64ea4c62d2aa382b176a4838474238f8d.tar.gz"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "fetchzip",
|
"method": "fetchzip",
|
||||||
|
@ -87,6 +109,67 @@
|
||||||
"sha256": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q",
|
"sha256": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q",
|
||||||
"srcDir": "src",
|
"srcDir": "src",
|
||||||
"url": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz"
|
"url": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"sys"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/vf9ls2wip6d8xhsi3rjh0dqsqg597i6b-source",
|
||||||
|
"rev": "c117ee60542f084525f254e6ade590675a6a2ed6",
|
||||||
|
"sha256": "12qzx2lnh84xqfgypy0pka8nflq0y8n1izfwx8mb4zya5nzawmyf",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://github.com/alaviss/nim-sys/archive/c117ee60542f084525f254e6ade590675a6a2ed6.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"taps"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/n86g5fw60z1k53bn35zvrwlwmyk3ixdn-source",
|
||||||
|
"rev": "756cb07b4f874181ad34c370cad6082ee65f646d",
|
||||||
|
"sha256": "0dp7ml3kj2fi6isvjkkxf02hwj0gshx6qra0ghnk2cbfykbcgfp8",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/756cb07b4f874181ad34c370cad6082ee65f646d.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2024-04-02T15:38:57+01:00",
|
||||||
|
"deepClone": false,
|
||||||
|
"fetchLFS": false,
|
||||||
|
"fetchSubmodules": true,
|
||||||
|
"hash": "sha256-iZb9aAgYr4FGkqfIg49QWiCqeizIi047kFhugHiP8o0=",
|
||||||
|
"leaveDotGit": false,
|
||||||
|
"method": "git",
|
||||||
|
"packages": [
|
||||||
|
"solo5_dispatcher"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/sf5dgj2ljvahcm6my7d61ibda51vnrii-solo5_dispatcher",
|
||||||
|
"rev": "a7a894a96a2221284012800e6fd32923d83d20bd",
|
||||||
|
"sha256": "13gjixw80vjqj0xlx2y85ixal82sa27q7j57j9383bqq11lgv5l9",
|
||||||
|
"srcDir": "pkg",
|
||||||
|
"url": "https://git.sr.ht/~ehmry/solo5_dispatcher"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"cps"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/phdf6siqbhj7vx4qq507lzla81si60iz-source",
|
||||||
|
"rev": "58772ff9ddb38a4b2ec52da142d8532ba2fe7039",
|
||||||
|
"sha256": "1lph7v27nqwgm3a0ssi8q348gjrkjwgqc50agw38j7xif6wj80cw",
|
||||||
|
"srcDir": "",
|
||||||
|
"url": "https://github.com/ehmry/cps/archive/58772ff9ddb38a4b2ec52da142d8532ba2fe7039.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"stew"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/mqg8qzsbcc8xqabq2yzvlhvcyqypk72c-source",
|
||||||
|
"rev": "3c91b8694e15137a81ec7db37c6c58194ec94a6a",
|
||||||
|
"sha256": "17lfhfxp5nxvld78xa83p258y80ks5jb4n53152cdr57xk86y07w",
|
||||||
|
"srcDir": "",
|
||||||
|
"url": "https://github.com/status-im/nim-stew/archive/3c91b8694e15137a81ec7db37c6c58194ec94a6a.tar.gz"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{ pkgs ? import <nixpkgs> { } }:
|
{ pkgs ? import <nixpkgs> { } }:
|
||||||
|
|
||||||
pkgs.buildNimPackage {
|
pkgs.buildNimPackage {
|
||||||
name = "dummy";
|
name = "dummy";
|
||||||
lockFile = ./lock.json;
|
lockFile = ./lock.json;
|
||||||
|
buildInputs = builtins.attrValues { inherit (pkgs) getdns solo5; };
|
||||||
|
nativeBuildInputs = builtins.attrValues { inherit (pkgs) pkg-config solo5; };
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,3 +186,15 @@ macro during*(turn: untyped; ds: Cap; pattern: Pattern; publishBody: untyped) =
|
||||||
raiseAssert($`pattern`.analyse.capturePaths.len & " values captured but handler has " & $`argCount` & " arguments - " & $`pattern`)
|
raiseAssert($`pattern`.analyse.capturePaths.len & " values captured but handler has " & $`argCount` & " arguments - " & $`pattern`)
|
||||||
`callbackProc`
|
`callbackProc`
|
||||||
discard observe(`turn`, `ds`, `pattern`, during(`callbackSym`))
|
discard observe(`turn`, `ds`, `pattern`, during(`callbackSym`))
|
||||||
|
|
||||||
|
when defined(solo5):
|
||||||
|
echo """
|
||||||
|
______
|
||||||
|
/ \_\
|
||||||
|
/ ,__/ \ ____ __
|
||||||
|
/\__/ \, \ _______ ______ ____/ /_/________ / /____
|
||||||
|
\/ \__/ / / ___/ / / / __ \/ __ / / ___/ __ \/ __/ _ \
|
||||||
|
\ ' \__/ _\_ \/ /_/ / / / / /_/ / / /__/ /_/ / /_/ __/
|
||||||
|
\____/_/ /____/\__, /_/ /_/\____/_/\___/\__/_/\__/\___/
|
||||||
|
/____/
|
||||||
|
"""
|
||||||
|
|
|
@ -1,18 +1,24 @@
|
||||||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[deques, hashes, monotimes, options, sets, tables, times]
|
import std/[assertions, deques, hashes, monotimes, options, sets, tables, times]
|
||||||
import pkg/cps
|
import cps
|
||||||
import pkg/sys/ioqueue
|
|
||||||
|
|
||||||
import preserves
|
import preserves
|
||||||
import ../syndicate/protocols/[protocol, sturdy, trace]
|
import ../syndicate/protocols/[protocol, sturdy]
|
||||||
|
import ../syndicate/protocols/trace
|
||||||
|
|
||||||
|
when defined(solo5):
|
||||||
|
import solo5_dispatcher
|
||||||
|
else:
|
||||||
|
import pkg/sys/ioqueue
|
||||||
|
|
||||||
const tracing = defined(traceSyndicate)
|
const tracing = defined(traceSyndicate)
|
||||||
|
|
||||||
when tracing:
|
when tracing:
|
||||||
import std/streams
|
import std/streams
|
||||||
from std/os import getEnv
|
when not defined(solo5):
|
||||||
|
from std/os import getEnv
|
||||||
|
|
||||||
export Handle
|
export Handle
|
||||||
|
|
||||||
|
@ -81,30 +87,41 @@ type
|
||||||
var turnQueue {.threadvar.}: Deque[Turn]
|
var turnQueue {.threadvar.}: Deque[Turn]
|
||||||
|
|
||||||
when tracing:
|
when tracing:
|
||||||
proc openTraceStream: FileStream =
|
when defined(solo5):
|
||||||
let path = getEnv("SYNDICATE_TRACE_FILE")
|
proc traceActivation(actor: Actor; act: ActorActivation) =
|
||||||
case path
|
discard #[
|
||||||
of "": stderr.writeLine "$SYNDICATE_TRACE_FILE unset"
|
echo TraceEntry(
|
||||||
of "-": result = newFileStream(stderr)
|
timestamp: getTime().toUnixFloat(),
|
||||||
else: result = openFileStream(path, fmWrite)
|
actor: initRecord("named", actor.name.toPreserves),
|
||||||
|
item: act,
|
||||||
|
).toPreserves
|
||||||
|
]#
|
||||||
|
else:
|
||||||
|
proc openTraceStream: FileStream =
|
||||||
|
let path = getEnv("SYNDICATE_TRACE_FILE")
|
||||||
|
case path
|
||||||
|
of "": stderr.writeLine "$SYNDICATE_TRACE_FILE unset"
|
||||||
|
of "-": result = newFileStream(stderr)
|
||||||
|
else: result = openFileStream(path, fmWrite)
|
||||||
|
|
||||||
|
let traceStream = openTraceStream()
|
||||||
|
|
||||||
|
proc traceActivation(actor: Actor; act: ActorActivation) =
|
||||||
|
if not traceStream.isNil:
|
||||||
|
var entry = TraceEntry(
|
||||||
|
timestamp: getTime().toUnixFloat(),
|
||||||
|
actor: initRecord("named", actor.name.toPreserves),
|
||||||
|
item: act)
|
||||||
|
traceStream.write(entry.toPreserves)
|
||||||
|
traceStream.flush()
|
||||||
|
|
||||||
let traceStream = openTraceStream()
|
|
||||||
var turnIdAllocator: uint
|
var turnIdAllocator: uint
|
||||||
|
|
||||||
proc nextTurnId(): TurnId =
|
proc nextTurnId(): TurnId =
|
||||||
inc(turnIdAllocator)
|
inc(turnIdAllocator)
|
||||||
turnIdAllocator.toPreserves
|
turnIdAllocator.toPreserves
|
||||||
|
|
||||||
proc trace(actor: Actor; act: ActorActivation) =
|
proc path(facet: Facet): seq[FacetId] =
|
||||||
if not traceStream.isNil:
|
|
||||||
var entry = TraceEntry(
|
|
||||||
timestamp: getTime().toUnixFloat(),
|
|
||||||
actor: initRecord("named", actor.name.toPreserves),
|
|
||||||
item: act)
|
|
||||||
traceStream.write(entry.toPreserves)
|
|
||||||
traceStream.flush()
|
|
||||||
|
|
||||||
proc path(facet: Facet): seq[trace.FacetId] =
|
|
||||||
var f = facet
|
var f = facet
|
||||||
while not f.isNil:
|
while not f.isNil:
|
||||||
result.add f.id.toPreserves
|
result.add f.id.toPreserves
|
||||||
|
@ -120,7 +137,7 @@ when tracing:
|
||||||
result = ActionDescription(orKind: ActionDescriptionKind.dequeue)
|
result = ActionDescription(orKind: ActionDescriptionKind.dequeue)
|
||||||
result.dequeue.event = move act.enqueue.event
|
result.dequeue.event = move act.enqueue.event
|
||||||
|
|
||||||
proc toTraceTarget(cap: Cap): trace.Target =
|
proc toTraceTarget(cap: Cap): Target =
|
||||||
assert not cap.target.isNil
|
assert not cap.target.isNil
|
||||||
assert not cap.target.facet.isNil
|
assert not cap.target.facet.isNil
|
||||||
result.actor = cap.target.facet.actor.id
|
result.actor = cap.target.facet.actor.id
|
||||||
|
@ -165,7 +182,6 @@ when tracing:
|
||||||
proc `$`*(r: Cap): string =
|
proc `$`*(r: Cap): string =
|
||||||
"<Ref:" & r.relay.labels & ">"
|
"<Ref:" & r.relay.labels & ">"
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(t: Turn): string =
|
proc `$`*(t: Turn): string =
|
||||||
"<Turn:" & $t.desc.id & ">"
|
"<Turn:" & $t.desc.id & ">"
|
||||||
|
|
||||||
|
@ -361,7 +377,7 @@ proc publish(turn: var Turn; cap: Cap; v: Value; h: Handle) =
|
||||||
act.enqueue.event.target.actor = turn.facet.actor.id.toPreserves
|
act.enqueue.event.target.actor = turn.facet.actor.id.toPreserves
|
||||||
act.enqueue.event.target.facet = turn.facet.id.toPreserves
|
act.enqueue.event.target.facet = turn.facet.id.toPreserves
|
||||||
act.enqueue.event.target.oid = cap.target.oid.toPreserves
|
act.enqueue.event.target.oid = cap.target.oid.toPreserves
|
||||||
act.enqueue.event.detail = trace.TurnEvent(orKind: TurnEventKind.assert)
|
act.enqueue.event.detail = trace.TurnEvent(orKind: trace.TurnEventKind.assert)
|
||||||
act.enqueue.event.detail.assert.assertion.value.value =
|
act.enqueue.event.detail.assert.assertion.value.value =
|
||||||
mapEmbeds(v) do (cap: Value) -> Value: discard
|
mapEmbeds(v) do (cap: Value) -> Value: discard
|
||||||
act.enqueue.event.detail.assert.handle = h
|
act.enqueue.event.detail.assert.handle = h
|
||||||
|
@ -532,7 +548,7 @@ proc newActor(name: string; parent: Facet): Actor =
|
||||||
var act = ActorActivation(orKind: ActorActivationKind.start)
|
var act = ActorActivation(orKind: ActorActivationKind.start)
|
||||||
act.start.actorName = Name(orKind: NameKind.named)
|
act.start.actorName = Name(orKind: NameKind.named)
|
||||||
act.start.actorName.named.name = name.toPreserves
|
act.start.actorName.named.name = name.toPreserves
|
||||||
trace(result, act)
|
traceActivation(result, act)
|
||||||
|
|
||||||
proc run(actor: Actor; bootProc: TurnAction; initialAssertions: OutboundTable) =
|
proc run(actor: Actor; bootProc: TurnAction; initialAssertions: OutboundTable) =
|
||||||
queueTurn(newFacet(actor, actor.root, initialAssertions), stopIfInertAfter(bootProc))
|
queueTurn(newFacet(actor, actor.root, initialAssertions), stopIfInertAfter(bootProc))
|
||||||
|
@ -603,7 +619,7 @@ proc terminateActor(turn; reason: ref Exception) =
|
||||||
if not reason.isNil:
|
if not reason.isNil:
|
||||||
act.stop.status = ExitStatus(orKind: ExitStatusKind.Error)
|
act.stop.status = ExitStatus(orKind: ExitStatusKind.Error)
|
||||||
act.stop.status.error.message = reason.msg
|
act.stop.status.error.message = reason.msg
|
||||||
trace(actor, act)
|
traceActivation(actor, act)
|
||||||
while actor.exitHooks.len > 0:
|
while actor.exitHooks.len > 0:
|
||||||
var hook = actor.exitHooks.pop()
|
var hook = actor.exitHooks.pop()
|
||||||
try: hook(turn)
|
try: hook(turn)
|
||||||
|
@ -704,7 +720,7 @@ proc run(turn: var Turn) =
|
||||||
when tracing:
|
when tracing:
|
||||||
var act = ActorActivation(orKind: ActorActivationKind.turn)
|
var act = ActorActivation(orKind: ActorActivationKind.turn)
|
||||||
act.turn = move turn.desc
|
act.turn = move turn.desc
|
||||||
trace(turn.facet.actor, act)
|
traceActivation(turn.facet.actor, act)
|
||||||
# TODO: catch exceptions here
|
# TODO: catch exceptions here
|
||||||
for eff in turn.effects.mvalues:
|
for eff in turn.effects.mvalues:
|
||||||
assert not eff.facet.isNil
|
assert not eff.facet.isNil
|
||||||
|
@ -717,30 +733,35 @@ proc runPendingTurns* =
|
||||||
# TODO: check if actor is still valid
|
# TODO: check if actor is still valid
|
||||||
try: run(turn)
|
try: run(turn)
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
stderr.writeLine("actor ", turn.actor.name, " threw an error during a turn")
|
|
||||||
terminateActor(turn, err)
|
terminateActor(turn, err)
|
||||||
|
raise err
|
||||||
|
|
||||||
proc run* =
|
proc run* =
|
||||||
## Run actors to completion
|
## Run actors to completion
|
||||||
var ready: seq[Continuation]
|
when defined(solo5):
|
||||||
while true:
|
while turnQueue.len > 0 or solo5_dispatcher.runOnce():
|
||||||
runPendingTurns()
|
runPendingTurns()
|
||||||
ioqueue.poll(ready)
|
else:
|
||||||
if ready.len == 0: break
|
var ready: seq[Continuation]
|
||||||
while ready.len > 0:
|
while true:
|
||||||
try:
|
runPendingTurns()
|
||||||
|
ioqueue.poll(ready)
|
||||||
|
if ready.len == 0: break
|
||||||
|
while ready.len > 0:
|
||||||
discard trampoline:
|
discard trampoline:
|
||||||
ready.pop()
|
ready.pop()
|
||||||
except CatchableError as err:
|
|
||||||
stderr.writeLine "ioqueue continuation threw an error"
|
|
||||||
raise err
|
|
||||||
|
|
||||||
proc runActor*(name: string; bootProc: TurnAction) =
|
proc runActor*(name: string; bootProc: TurnAction) =
|
||||||
## Boot an actor `Actor` and churn ioqueue.
|
## Boot an actor `Actor` and churn ioqueue.
|
||||||
let actor = bootActor(name, bootProc)
|
let actor = bootActor(name, bootProc)
|
||||||
if not actor.exitReason.isNil:
|
if not actor.exitReason.isNil:
|
||||||
raise actor.exitReason
|
raise actor.exitReason
|
||||||
actors.run()
|
when defined(solo5):
|
||||||
|
runPendingTurns()
|
||||||
|
while (actor.isAlive and solo5_dispatcher.runOnce()) or turnQueue.len > 0:
|
||||||
|
runPendingTurns()
|
||||||
|
else:
|
||||||
|
actors.run()
|
||||||
if not actor.exitReason.isNil:
|
if not actor.exitReason.isNil:
|
||||||
raise actor.exitReason
|
raise actor.exitReason
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,48 @@
|
||||||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[sets, times]
|
import std/times
|
||||||
import pkg/sys/[handles, ioqueue]
|
|
||||||
import preserves
|
import preserves
|
||||||
import ../../syndicate, ../bags, ../protocols/[timer, dataspace]
|
import ../../syndicate, ../bags, ../protocols/[timer, dataspace]
|
||||||
|
|
||||||
|
when defined(solo5):
|
||||||
|
import solo5_dispatcher
|
||||||
|
else:
|
||||||
|
import pkg/sys/[handles, ioqueue]
|
||||||
|
|
||||||
export timer
|
export timer
|
||||||
|
|
||||||
type
|
type
|
||||||
Observe = dataspace.Observe
|
Observe = dataspace.Observe
|
||||||
|
|
||||||
when defined(linux):
|
when defined(solo5):
|
||||||
import std/[oserrors, posix]
|
import solo5, solo5_dispatcher
|
||||||
|
|
||||||
|
proc wallFloat: float =
|
||||||
|
solo5_clock_wall().float / 1_000_000_000.0
|
||||||
|
|
||||||
|
type
|
||||||
|
TimerDriver = ref object
|
||||||
|
facet: Facet
|
||||||
|
## Owning facet of driver.
|
||||||
|
target: Cap
|
||||||
|
## Destination for LaterThan assertions.
|
||||||
|
deadlines: Bag[float]
|
||||||
|
## Deadlines that other actors are observing.
|
||||||
|
|
||||||
|
proc spawnTimerDriver(facet: Facet; cap: Cap): TimerDriver =
|
||||||
|
TimerDriver(facet: facet, target: cap)
|
||||||
|
|
||||||
|
proc await(driver: TimerDriver; deadline: float) {.solo5dispatch.} =
|
||||||
|
yieldUntil(deadline)
|
||||||
|
if deadline in driver.deadlines:
|
||||||
|
# check if the deadline is still observed
|
||||||
|
proc turnWork(turn: var Turn) =
|
||||||
|
discard publish(turn, driver.target, LaterThan(seconds: deadline))
|
||||||
|
run(driver.facet, turnWork)
|
||||||
|
|
||||||
|
else:
|
||||||
|
import std/[oserrors, posix, sets]
|
||||||
type Time = posix.Time
|
type Time = posix.Time
|
||||||
|
|
||||||
{.pragma: timerfd, importc, header: "<sys/timerfd.h>".}
|
{.pragma: timerfd, importc, header: "<sys/timerfd.h>".}
|
||||||
|
@ -42,9 +72,11 @@ when defined(linux):
|
||||||
result.tv_sec = Time(f)
|
result.tv_sec = Time(f)
|
||||||
result.tv_nsec = clong(uint64(f * 1_000_000_000) mod 1_000_000_000)
|
result.tv_nsec = clong(uint64(f * 1_000_000_000) mod 1_000_000_000)
|
||||||
|
|
||||||
proc clock_realtime: Timespec =
|
proc wallFloat: float =
|
||||||
if clock_gettime(CLOCK_REALTIME, result) < 0:
|
var ts: Timespec
|
||||||
|
if clock_gettime(CLOCK_REALTIME, ts) < 0:
|
||||||
raiseOSError(osLastError(), "clock_gettime")
|
raiseOSError(osLastError(), "clock_gettime")
|
||||||
|
ts.toFloat
|
||||||
|
|
||||||
type
|
type
|
||||||
TimerDriver = ref object
|
TimerDriver = ref object
|
||||||
|
@ -83,7 +115,7 @@ when defined(linux):
|
||||||
if timerfd_settime(fd, TFD_TIMER_ABSTIME, its, old) < 0:
|
if timerfd_settime(fd, TFD_TIMER_ABSTIME, its, old) < 0:
|
||||||
raiseOSError(osLastError(), "failed to set timeout")
|
raiseOSError(osLastError(), "failed to set timeout")
|
||||||
driver.timers.incl(fd)
|
driver.timers.incl(fd)
|
||||||
while clock_realtime() < its.it_value:
|
while wallFloat() < deadline:
|
||||||
# Check if the timer is expired which
|
# Check if the timer is expired which
|
||||||
# could happen before waiting.
|
# could happen before waiting.
|
||||||
wait(FD fd, Read)
|
wait(FD fd, Read)
|
||||||
|
@ -95,21 +127,21 @@ when defined(linux):
|
||||||
discard close(fd)
|
discard close(fd)
|
||||||
driver.timers.excl(fd)
|
driver.timers.excl(fd)
|
||||||
|
|
||||||
proc spawnTimerActor*(turn: var Turn; ds: Cap): Actor {.discardable.} =
|
proc spawnTimerActor*(turn: var Turn; ds: Cap): Actor {.discardable.} =
|
||||||
## Spawn a timer actor that responds to
|
## Spawn a timer actor that responds to
|
||||||
## dataspace observations of timeouts on `ds`.
|
## dataspace observations of timeouts on `ds`.
|
||||||
linkActor("timers", turn) do (turn: var Turn):
|
linkActor(turn, "timers") do (turn: var Turn):
|
||||||
let driver = spawnTimerDriver(turn.facet, ds)
|
let driver = spawnTimerDriver(turn.facet, ds)
|
||||||
let pat = inject(grab Observe(pattern: dropType LaterThan), {0: grabLit()})
|
let pat = inject(grab Observe(pattern: dropType LaterThan), {0: grabLit()})
|
||||||
during(turn, ds, pat) do (deadline: float):
|
during(turn, ds, pat) do (deadline: float):
|
||||||
if change(driver.deadlines, deadline, +1) == cdAbsentToPresent:
|
if change(driver.deadlines, deadline, +1) == cdAbsentToPresent:
|
||||||
discard trampoline(whelp await(driver, deadline))
|
discard trampoline(whelp await(driver, deadline))
|
||||||
do:
|
do:
|
||||||
discard change(driver.deadlines, deadline, -1, clamp = true)
|
discard change(driver.deadlines, deadline, -1, clamp = true)
|
||||||
# TODO: retract assertions that are unobserved.
|
# TODO: retract assertions that are unobserved.
|
||||||
|
|
||||||
proc after*(turn: var Turn; ds: Cap; dur: Duration; act: TurnAction) =
|
proc after*(turn: var Turn; ds: Cap; dur: Duration; act: TurnAction) =
|
||||||
## Execute `act` after some duration of time.
|
## Execute `act` after some duration of time.
|
||||||
var later = clock_realtime().toFloat() + dur.inMilliseconds.float / 1_000.0
|
var later = wallFloat() + dur.inMilliseconds.float / 1_000.0
|
||||||
onPublish(turn, ds, grab LaterThan(seconds: later)):
|
onPublish(turn, ds, grab LaterThan(seconds: later)):
|
||||||
act(turn)
|
act(turn)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
## An unordered association of items to counts.
|
## An unordered association of items to counts.
|
||||||
## An item count may be negative, unlike CountTable.
|
## An item count may be negative, unlike CountTable.
|
||||||
|
|
||||||
import tables
|
import std/[assertions, tables]
|
||||||
|
|
||||||
type
|
type
|
||||||
ChangeDescription* = enum
|
ChangeDescription* = enum
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[algorithm, options, sequtils, tables, typetraits]
|
import std/[algorithm, assertions, options, sequtils, tables, typetraits]
|
||||||
|
|
||||||
import preserves
|
import preserves
|
||||||
import ./protocols/dataspacePatterns
|
import ./protocols/dataspacePatterns
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[options, tables]
|
import std/[options, tables]
|
||||||
from std/os import getEnv, `/`
|
|
||||||
import pkg/sys/ioqueue
|
|
||||||
import preserves
|
import preserves
|
||||||
import ../syndicate, /capabilities, ./durings, ./membranes, ./protocols/[gatekeeper, protocol, sturdy, transportAddress]
|
import ../syndicate, ./durings, ./membranes, ./protocols/[gatekeeper, protocol, sturdy, transportAddress]
|
||||||
|
|
||||||
|
when defined(posix):
|
||||||
|
import ./capabilities
|
||||||
|
from std/os import getEnv, `/`
|
||||||
|
|
||||||
when defined(traceSyndicate):
|
when defined(traceSyndicate):
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
|
@ -17,7 +19,7 @@ else:
|
||||||
|
|
||||||
export `$`
|
export `$`
|
||||||
|
|
||||||
export Stdio, Tcp, WebSocket, Unix
|
export Route, Stdio, Tcp, WebSocket, Unix
|
||||||
|
|
||||||
type
|
type
|
||||||
Assertion = Value
|
Assertion = Value
|
||||||
|
@ -249,6 +251,11 @@ proc recv(relay: Relay; buf: openarray[byte]; slice: Slice[int]) =
|
||||||
var pr = decode(relay.wireBuf)
|
var pr = decode(relay.wireBuf)
|
||||||
if pr.isSome: dispatch(relay, pr.get)
|
if pr.isSome: dispatch(relay, pr.get)
|
||||||
|
|
||||||
|
proc recv(relay: Relay; buf: openarray[byte]) =
|
||||||
|
feed(relay.wireBuf, buf)
|
||||||
|
var pr = decode(relay.wireBuf)
|
||||||
|
if pr.isSome: dispatch(relay, pr.get)
|
||||||
|
|
||||||
type
|
type
|
||||||
RelayOptions* = object of RootObj
|
RelayOptions* = object of RootObj
|
||||||
packetWriter*: PacketWriter
|
packetWriter*: PacketWriter
|
||||||
|
@ -292,10 +299,14 @@ proc accepted(cap: Cap): Resolved =
|
||||||
result = Resolved(orKind: ResolvedKind.accepted)
|
result = Resolved(orKind: ResolvedKind.accepted)
|
||||||
result.accepted.responderSession = cap
|
result.accepted.responderSession = cap
|
||||||
|
|
||||||
|
type ShutdownEntity = ref object of Entity
|
||||||
|
method retract(e: ShutdownEntity; turn: var Turn; h: Handle) =
|
||||||
|
stopActor(e.facet)
|
||||||
|
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
|
|
||||||
import std/[oserrors, posix]
|
import std/[oserrors, posix]
|
||||||
import pkg/sys/[files, handles, sockets]
|
import pkg/sys/[files, handles, ioqueue, sockets]
|
||||||
export transportAddress.Unix
|
export transportAddress.Unix
|
||||||
|
|
||||||
type StdioEntity = ref object of Entity
|
type StdioEntity = ref object of Entity
|
||||||
|
@ -375,10 +386,6 @@ when defined(posix):
|
||||||
if ass.value.preservesTo(ForceDisconnect).isSome:
|
if ass.value.preservesTo(ForceDisconnect).isSome:
|
||||||
entity.alive = false
|
entity.alive = false
|
||||||
|
|
||||||
type ShutdownEntity = ref object of Entity
|
|
||||||
method retract(e: ShutdownEntity; turn: var Turn; h: Handle) =
|
|
||||||
stopActor(e.facet)
|
|
||||||
|
|
||||||
template bootSocketEntity() {.dirty.} =
|
template bootSocketEntity() {.dirty.} =
|
||||||
proc setup(turn: var Turn) {.closure.} =
|
proc setup(turn: var Turn) {.closure.} =
|
||||||
proc kill(turn: var Turn) =
|
proc kill(turn: var Turn) =
|
||||||
|
@ -434,6 +441,73 @@ when defined(posix):
|
||||||
let entity = UnixEntity()
|
let entity = UnixEntity()
|
||||||
spawnSocketRelay()
|
spawnSocketRelay()
|
||||||
|
|
||||||
|
elif defined(solo5):
|
||||||
|
|
||||||
|
import solo5_dispatcher
|
||||||
|
import taps
|
||||||
|
|
||||||
|
type
|
||||||
|
TcpEntity = ref object of Entity
|
||||||
|
relay: Relay
|
||||||
|
conn: Connection
|
||||||
|
decoder: BufferedDecoder
|
||||||
|
|
||||||
|
method message(entity: TcpEntity; turn: var Turn; ass: AssertionRef) =
|
||||||
|
if ass.value.preservesTo(ForceDisconnect).isSome:
|
||||||
|
entity.conn.abort()
|
||||||
|
|
||||||
|
proc connectTransport(turn: var Turn; ds: Cap; ta: transportAddress.Tcp) =
|
||||||
|
let entity = TcpEntity(facet: turn.facet)
|
||||||
|
|
||||||
|
proc writeConn(turn: var Turn; buf: seq[byte]) =
|
||||||
|
assert not entity.conn.isNil
|
||||||
|
entity.conn.batch:
|
||||||
|
entity.conn.send(buf)
|
||||||
|
var ops = RelayActorOptions(
|
||||||
|
packetWriter: writeConn,
|
||||||
|
initialOid: 0.Oid.some,
|
||||||
|
)
|
||||||
|
spawnRelay("socket", turn, ops) do (turn: var Turn; relay: Relay):
|
||||||
|
entity.facet = turn.facet
|
||||||
|
entity.relay = relay
|
||||||
|
|
||||||
|
var ep = newRemoteEndpoint()
|
||||||
|
if ta.host.isIpAddress:
|
||||||
|
ep.with ta.host.parseIpAddress
|
||||||
|
else:
|
||||||
|
ep.withHostname ta.host
|
||||||
|
ep.with ta.port.Port
|
||||||
|
|
||||||
|
var tp = newTransportProperties()
|
||||||
|
tp.require "reliability"
|
||||||
|
tp.ignore "congestion-control"
|
||||||
|
tp.ignore "preserve-order"
|
||||||
|
|
||||||
|
var preconn = newPreconnection(
|
||||||
|
remote=[ep], transport=tp.some)
|
||||||
|
entity.conn = preconn.initiate()
|
||||||
|
entity.facet.onStop do (turn: var Turn):
|
||||||
|
entity.conn.close()
|
||||||
|
entity.conn.onConnectionError do (err: ref Exception):
|
||||||
|
run(entity.facet) do (turn: var Turn):
|
||||||
|
terminate(turn, err)
|
||||||
|
entity.conn.onClosed():
|
||||||
|
stop(entity.facet)
|
||||||
|
entity.conn.onReceivedPartial do (data: seq[byte]; ctx: MessageContext; eom: bool):
|
||||||
|
entity.relay.recv(data)
|
||||||
|
if eom:
|
||||||
|
stop(entity.facet)
|
||||||
|
else:
|
||||||
|
entity.conn.receive()
|
||||||
|
entity.conn.onReady do ():
|
||||||
|
entity.facet.run do (turn: var Turn):
|
||||||
|
publish(turn, ds, TransportConnection(
|
||||||
|
`addr`: ta.toPreserves,
|
||||||
|
control: newCap(entity, turn),
|
||||||
|
resolved: entity.relay.peer.accepted,
|
||||||
|
))
|
||||||
|
entity.conn.receive()
|
||||||
|
|
||||||
proc walk(turn: var Turn; ds, origin: Cap; route: Route; transOff, stepOff: int) =
|
proc walk(turn: var Turn; ds, origin: Cap; route: Route; transOff, stepOff: int) =
|
||||||
if stepOff < route.pathSteps.len:
|
if stepOff < route.pathSteps.len:
|
||||||
let
|
let
|
||||||
|
@ -503,9 +577,19 @@ proc spawnRelays*(turn: var Turn; ds: Cap) =
|
||||||
# Use a generic pattern and type matching
|
# Use a generic pattern and type matching
|
||||||
# in the during handler because it is easy.
|
# in the during handler because it is easy.
|
||||||
|
|
||||||
let stdioPat = ?Observe(pattern: TransportConnection?:{0: ?:Stdio})
|
when defined(posix):
|
||||||
during(turn, ds, stdioPat) do:
|
let stdioPat = ?Observe(pattern: TransportConnection?:{0: ?:Stdio})
|
||||||
connectTransport(turn, ds, Stdio())
|
during(turn, ds, stdioPat) do:
|
||||||
|
connectTransport(turn, ds, Stdio())
|
||||||
|
|
||||||
|
# TODO: unix pattern
|
||||||
|
during(turn, ds, transPat) do (ta: Literal[transportAddress.Unix]):
|
||||||
|
try: connectTransport(turn, ds, ta.value)
|
||||||
|
except exceptions.IOError as e:
|
||||||
|
publish(turn, ds, TransportConnection(
|
||||||
|
`addr`: ta.toPreserve,
|
||||||
|
resolved: rejected(embed e),
|
||||||
|
))
|
||||||
|
|
||||||
# TODO: tcp pattern
|
# TODO: tcp pattern
|
||||||
during(turn, ds, transPat) do (ta: Literal[transportAddress.Tcp]):
|
during(turn, ds, transPat) do (ta: Literal[transportAddress.Tcp]):
|
||||||
|
@ -516,15 +600,6 @@ proc spawnRelays*(turn: var Turn; ds: Cap) =
|
||||||
resolved: rejected(embed e),
|
resolved: rejected(embed e),
|
||||||
))
|
))
|
||||||
|
|
||||||
# TODO: unix pattern
|
|
||||||
during(turn, ds, transPat) do (ta: Literal[transportAddress.Unix]):
|
|
||||||
try: connectTransport(turn, ds, ta.value)
|
|
||||||
except exceptions.IOError as e:
|
|
||||||
publish(turn, ds, TransportConnection(
|
|
||||||
`addr`: ta.toPreserve,
|
|
||||||
resolved: rejected(embed e),
|
|
||||||
))
|
|
||||||
|
|
||||||
let resolvePat = ?Observe(pattern: !ResolvePath) ?? {0: grab()}
|
let resolvePat = ?Observe(pattern: !ResolvePath) ?? {0: grab()}
|
||||||
during(turn, ds, resolvePat) do (route: Literal[Route]):
|
during(turn, ds, resolvePat) do (route: Literal[Route]):
|
||||||
for i, transAddr in route.value.transports:
|
for i, transAddr in route.value.transports:
|
||||||
|
@ -537,41 +612,42 @@ proc spawnRelays*(turn: var Turn; ds: Cap) =
|
||||||
|
|
||||||
type BootProc* = proc (turn: var Turn; ds: Cap) {.closure.}
|
type BootProc* = proc (turn: var Turn; ds: Cap) {.closure.}
|
||||||
|
|
||||||
const defaultRoute* = "<route [<stdio>]>"
|
|
||||||
|
|
||||||
proc envRoute*: Route =
|
|
||||||
## Get an route to a Syndicate capability from the calling environment.
|
|
||||||
## On UNIX this is the SYNDICATE_ROUTE environmental variable with a
|
|
||||||
## fallack to a defaultRoute_.
|
|
||||||
## See https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/raw/branch/main/schemas/gatekeeper.prs.
|
|
||||||
var text = getEnv("SYNDICATE_ROUTE", defaultRoute)
|
|
||||||
if text == "":
|
|
||||||
var tx = (getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace").toPreserves
|
|
||||||
result.transports = @[initRecord("unix", tx)]
|
|
||||||
result.pathSteps = @[capabilities.mint().toPreserves]
|
|
||||||
else:
|
|
||||||
var pr = parsePreserves(text)
|
|
||||||
if not result.fromPreserves(pr):
|
|
||||||
raise newException(ValueError, "failed to parse $SYNDICATE_ROUTE " & $pr)
|
|
||||||
|
|
||||||
proc resolve*(turn: var Turn; ds: Cap; route: Route; bootProc: BootProc) =
|
proc resolve*(turn: var Turn; ds: Cap; route: Route; bootProc: BootProc) =
|
||||||
## Resolve `route` within `ds` and call `bootProc` with resolved capabilities.
|
## Resolve `route` within `ds` and call `bootProc` with resolved capabilities.
|
||||||
during(turn, ds, ResolvePath ?: {0: ?route, 3: ?:ResolvedAccepted}) do (dst: Cap):
|
during(turn, ds, ResolvePath ?: {0: ?route, 3: ?:ResolvedAccepted}) do (dst: Cap):
|
||||||
bootProc(turn, dst)
|
bootProc(turn, dst)
|
||||||
|
|
||||||
proc resolveEnvironment*(turn: var Turn; bootProc: BootProc) =
|
when defined(posix):
|
||||||
## Resolve a capability from the calling environment
|
const defaultRoute* = "<route [<stdio>]>"
|
||||||
## and call `bootProc`. See envRoute_.
|
|
||||||
var resolved = false
|
proc envRoute*: Route =
|
||||||
let
|
## Get an route to a Syndicate capability from the calling environment.
|
||||||
ds = newDataspace(turn)
|
## On UNIX this is the SYNDICATE_ROUTE environmental variable with a
|
||||||
pat = ResolvePath ?: {0: ?envRoute(), 3: ?:ResolvedAccepted}
|
## fallack to a defaultRoute_.
|
||||||
during(turn, ds, pat) do (dst: Cap):
|
## See https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/raw/branch/main/schemas/gatekeeper.prs.
|
||||||
if not resolved:
|
var text = getEnv("SYNDICATE_ROUTE", defaultRoute)
|
||||||
resolved = true
|
if text == "":
|
||||||
bootProc(turn, dst)
|
var tx = (getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace").toPreserves
|
||||||
do:
|
result.transports = @[initRecord("unix", tx)]
|
||||||
resolved = false
|
result.pathSteps = @[capabilities.mint().toPreserves]
|
||||||
spawnRelays(turn, ds)
|
else:
|
||||||
|
var pr = parsePreserves(text)
|
||||||
|
if not result.fromPreserves(pr):
|
||||||
|
raise newException(ValueError, "failed to parse $SYNDICATE_ROUTE " & $pr)
|
||||||
|
|
||||||
|
proc resolveEnvironment*(turn: var Turn; bootProc: BootProc) =
|
||||||
|
## Resolve a capability from the calling environment
|
||||||
|
## and call `bootProc`. See envRoute_.
|
||||||
|
var resolved = false
|
||||||
|
let
|
||||||
|
ds = newDataspace(turn)
|
||||||
|
pat = ResolvePath ?: {0: ?envRoute(), 3: ?:ResolvedAccepted}
|
||||||
|
during(turn, ds, pat) do (dst: Cap):
|
||||||
|
if not resolved:
|
||||||
|
resolved = true
|
||||||
|
bootProc(turn, dst)
|
||||||
|
do:
|
||||||
|
resolved = false
|
||||||
|
spawnRelays(turn, ds)
|
||||||
|
|
||||||
# TODO: define a runActor that comes preloaded with relaying
|
# TODO: define a runActor that comes preloaded with relaying
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
## https://git.syndicate-lang.org/syndicate-lang/syndicate-rkt/src/commit/90c4c60699069b496491b81ee63b5a45ffd638cb/syndicate/HOWITWORKS.md
|
## https://git.syndicate-lang.org/syndicate-lang/syndicate-rkt/src/commit/90c4c60699069b496491b81ee63b5a45ffd638cb/syndicate/HOWITWORKS.md
|
||||||
|
|
||||||
import std/[hashes, options, sets, tables]
|
import std/[assertions, hashes, options, sets, tables]
|
||||||
import preserves
|
import preserves
|
||||||
import ./actors, ./bags, ./patterns
|
import ./actors, ./bags, ./patterns
|
||||||
import ./protocols/dataspacePatterns
|
import ./protocols/dataspacePatterns
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "20240327"
|
version = "20240402"
|
||||||
author = "Emery Hemingway"
|
author = "Emery Hemingway"
|
||||||
description = "Syndicated actors for conversational concurrency"
|
description = "Syndicated actors for conversational concurrency"
|
||||||
license = "Unlicense"
|
license = "Unlicense"
|
||||||
|
@ -9,4 +9,4 @@ srcDir = "src"
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "https://github.com/ehmry/hashlib.git >= 20231130", "nim >= 2.0.0", "https://git.syndicate-lang.org/ehmry/preserves-nim.git >= 20240312", "https://github.com/ehmry/nim-sys.git#4ef3b624db86e331ba334e705c1aa235d55b05e1", "https://github.com/nim-works/cps"
|
requires "https://github.com/ehmry/hashlib.git >= 20231130", "nim >= 2.0.0", "https://git.syndicate-lang.org/ehmry/preserves-nim.git >= 20240312", "https://github.com/ehmry/nim-sys.git#4ef3b624db86e331ba334e705c1aa235d55b05e1", "https://git.sr.ht/~ehmry/nim_taps >= 20240402"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
include_rules
|
include_rules
|
||||||
: foreach *.prs |> !preserves_schema_nim |> | {schema}
|
: foreach *.prs |> !preserves_schema_nim |> | {schema}
|
||||||
: foreach t*.nim | ../../preserves-nim/<tests> {schema} $(SYNDICATE_PROTOCOL) |> !nim_run |> | ../<test>
|
: foreach t*.nim | ../../preserves-nim/<tests> {schema} $(SYNDICATE_PROTOCOL) |> !nim_run |> | ../<test>
|
||||||
|
: foreach solo5*.nim | ../../taps/<sources> ../../preserves-nim/<tests> {schema} $(SYNDICATE_PROTOCOL) |> !nim_solo5_spt |> | ../<test>
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/times
|
import std/times
|
||||||
import pkg/sys/ioqueue
|
|
||||||
import syndicate, syndicate/actors/timers
|
import syndicate, syndicate/actors/timers
|
||||||
|
|
||||||
let actor = bootActor("timer-test") do (turn: var Turn):
|
runActor("timer-test") do (turn: var Turn):
|
||||||
let timers = newDataspace(turn)
|
let timers = newDataspace(turn)
|
||||||
spawnTimerActor(turn, timers)
|
spawnTimerActor(turn, timers)
|
||||||
|
|
||||||
|
@ -21,6 +20,3 @@ let actor = bootActor("timer-test") do (turn: var Turn):
|
||||||
|
|
||||||
after(turn, timers, initDuration(seconds = 2)) do (turn: var Turn):
|
after(turn, timers, initDuration(seconds = 2)) do (turn: var Turn):
|
||||||
echo "second timer expired"
|
echo "second timer expired"
|
||||||
|
|
||||||
echo "single run of ioqueue"
|
|
||||||
ioqueue.run()
|
|
||||||
|
|
Loading…
Reference in New Issue