Compare commits

...

12 Commits

Author SHA1 Message Date
Emery Hemingway 32f8cd792c Add esc_printer_actor 2024-05-30 22:46:15 +03:00
Emery Hemingway 1bf29bdf02 syndump: fix double pattern binding
This happened because the semantics of bind(Value) changed from a
drop to a bind.
2024-05-30 20:52:26 +03:00
Emery Hemingway 6a7646ff54 Replace Nimble with CycloneDX 2024-05-30 20:52:26 +03:00
Emery Hemingway dc134898b5 Update dependencies
Use nimcrypto rather than hashlib.
Hashlib depends on nimcrypto anyway.
2024-05-30 20:51:58 +03:00
Emery Hemingway 3a0bd1cd02 Make a proper default.nix, cleanup lockfile 2024-05-10 12:08:51 +02:00
Emery Hemingway cda940cf75 Update syndicate dependency 2024-05-09 18:31:20 +02:00
Emery Hemingway bf0b5d6b86 Add http_client 2024-05-09 18:31:20 +02:00
Emery Hemingway b3a417a072 Replace "var Turn" with "Turn" 2024-04-30 13:56:48 +02:00
Emery Hemingway 48408d2763 Use new dataspace patterns 2024-04-23 10:25:03 +02:00
Emery Hemingway 494418540a Update syndicate library 2024-04-09 10:14:58 +01:00
Emery Hemingway e954fdefec SQL: decompose SQL statements and assert errors 2024-04-09 10:14:38 +01:00
Emery Hemingway de7683b467 Add http driver to README 2024-04-08 14:10:34 +01:00
31 changed files with 1330 additions and 392 deletions

137
README.md
View File

@ -47,6 +47,46 @@ Query the size of a directory in bytes by observing `<file-system-usage "/SOME/P
]
```
### HTTP driver
Experimental HTTP server that services requests using [some version](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/commit/9864ce0ec86fb2f916c2aab318a1e6994ab8834c/schemas/http.prs) of the http Syndicate protocol schema.
```
# Configuration example
let ?not-found = dataspace
$not-found ? <request _ ?res> [
$res ! <status 503 "Service unavailable">
$res ! <done "No binding here.">
]
let ?greeting = dataspace
$greeting ? <request _ ?res> [
$res ! <status 200 "ok">
$res ! <chunk "Hello world">
$res ! <done "!">
]
let ?http = dataspace
$http [
<http-bind #f 80 get [ ] $not-found>
<http-bind #f 80 get [|...|] $not-found>
<http-bind #f 80 get ["hello"] $greeting>
]
? <service-object <daemon http-driver> ?cap> [
$cap <http-driver { dataspace: $http }>
]
<daemon http-driver {
argv: [ "/bin/syndesizer" ]
clearEnv: #t
protocol: application/syndicate
}>
<require-service <daemon http-driver>>
```
### JSON Socket Translator
Communicate with sockets that send and receive lines of JSON using `<send …>` and `<recv …>` messages.
@ -168,9 +208,14 @@ let ?tuplespace = dataspace
$sqlspace <query "SELECT id, name FROM stuff" $tuplespace>
$tuplespace ? [?id ?name] [
$tuplespace [
? [?id ?name] [
$log ! <log "-" { row: <example-row $id $name> }>
]
? <sqlite-error ?msg ?ctx> [
$log ! <log "-" { msg: $msg ctx: $ctx }>
]
]
```
### XML translator
@ -196,6 +241,96 @@ Examples:
---
## esc_printer_actor
A basic [ESC/P](https://en.wikipedia.org/wiki/ESC/P) printer controller.
Takes a path to a printer device file as a command line argument and publishes a `<printer @cap #:any @device-path string>` to its environment.
The capability in this assertion is an entity that prints the strings it receives as messages.
While the `<bold>` or `<italic>` is asserted to this entity the printer will go into the corresponding font mode (if the printer supports it).
Sample Syndicate server script:
```
<require-service <daemon printer>>
? <printer ?printer> [
$log ?? <log "-" { line: ?line }> [
$printer ! $text
$printer ! "\r\n"
# Print log messages.
]
]
? <service-object <daemon printer> ?cap> [
$cap ? <printer ?printer ?device> [
$config <printer $printer>
]
]
<daemon printer {
argv: [ "/bin/esc_printer_actor" "/dev/usb/lp0"]
protocol: application/syndicate
}>
```
## http_client
The inverse of `http-driver`.
### Caveats
- HTTPS is assumed unless the request is to port 80.
- If the request or response sets `Content-Type` to `application/json` or `…/preserves`
the body will be a parsed Preserves value.
- No cache support.
- Internal errors propagate using a `400 Internal client error` response.
Sample Syndicate server script:
```
# A top-level dataspace
let ?ds = dataspace
# A dataspace for handling the HTTP response.
let ?response = dataspace
$response [
?? <done { "code": "EUR" "exchange_middle": ?middle } > [
$ds <exchange EUR RSD $middle>
]
]
$ds [
<request
# Request Euro to Dinar exchange rate.
<http-request 0 "kurs.resenje.org" 443
get ["api" "v1" "currencies" "eur" "rates" "today"]
{Content-Type: "application/json"} {} #f
>
$response
>
# Log all assertions.
? ?any [
$log ! <log "-" { assertion: $any }>
]
]
? <service-object <daemon http-client> ?cap> [
$cap <http-client {
dataspace: $ds
}>
]
<require-service <daemon http-client>>
? <built http-client ?path ?sum> [
<daemon http-client {
argv: [ "/bin/http_client" ]
clearEnv: #t
protocol: application/syndicate
}>
]
```
## mintsturdyref
A utility for minting [Sturdyrefs](https://synit.org/book/operation/builtin/gatekeeper.html#sturdyrefs).

View File

@ -1,3 +1,2 @@
include_rules
: |> !nim_lk |> {lockfile}
: {lockfile} |> !nim_cfg |> | ./<lock>
: sbom.json |> !sbom-to-nix |> | ./<lock>

View File

@ -26,6 +26,10 @@ UnixAddress = <unix @path string>.
SocketAddress = TcpAddress / UnixAddress .
HttpClientArguments = <http-client {
dataspace: #:any
}>.
HttpDriverArguments = <http-driver {
dataspace: #:any
}>.

19
default.nix Normal file
View File

@ -0,0 +1,19 @@
{
pkgs ? import <nixpkgs> { },
}:
with pkgs;
let
buildNimSbom = pkgs.callPackage (import <build-nim-sbom.nix>) { };
in
buildNimSbom ./sbom.json (
final: prev: {
src = if lib.inNixShell then null else lib.cleanSource ./.;
buildInputs = [
postgresql.out
sqlite
libxml2
libxslt
openssl
];
}
)

265
lock.json
View File

@ -1,5 +1,22 @@
{
"depends": [
{
"date": "2024-05-23T17:44:14+03:00",
"deepClone": false,
"fetchLFS": false,
"fetchSubmodules": true,
"hash": "sha256-qTRhHsOPNov1BQcm3P7NEkEPW6uh80XFfQRBdMp4o0Q=",
"leaveDotGit": false,
"method": "git",
"packages": [
"syndicate"
],
"path": "/nix/store/1lcxrap5n80hy1z4bcmsmdx83n4b9wjf-syndicate-nim",
"rev": "7ab4611824b676157523f2618e7893d5ac99e4f2",
"sha256": "0i53g3578h84gp2lbwx1mddhyh8jrpzdq9h70psqndlgqcg62d59",
"srcDir": "src",
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim.git"
},
{
"method": "fetchzip",
"packages": [
@ -22,166 +39,6 @@
"srcDir": "",
"url": "https://github.com/ehmry/cps/archive/c90530ac57f98a842b7be969115c6ef08bdcc564.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"cps"
],
"path": "/nix/store/8gbhwni0akqskdb3qhn5nfgv6gkdz0vz-source",
"rev": "c90530ac57f98a842b7be969115c6ef08bdcc564",
"sha256": "0h8ghs2fqg68j3jdcg7grnxssmllmgg99kym2w0a3vlwca1zvr62",
"srcDir": "",
"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",
"packages": [
"hashlib"
],
"path": "/nix/store/fav82xdbicvlk34nmcbl89zx99lr3mbs-source",
"rev": "f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac",
"sha256": "1sx6j952lj98629qfgr7ds5aipyw9d6lldcnnqs205wpj4pkcjb3",
"srcDir": "",
"url": "https://github.com/ehmry/hashlib/archive/f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"preserves"
],
"path": "/nix/store/2hy124xgabz134dxj3wji7mp47fdwy3w-source",
"rev": "9ae435a83c6d5028405538af5d24a023af625b6e",
"sha256": "1k7ywcp1a53x2fpc6wc2b0qzb264dkifash0s1wcp66rw3lx15k2",
"srcDir": "src",
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/9ae435a83c6d5028405538af5d24a023af625b6e.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"
},
{
"method": "fetchzip",
"packages": [
"syndicate"
],
"path": "/nix/store/kl628g7vg2ww8wilf8h2ag7qqnvvwdzb-source",
"rev": "c2e1e2e0fa403529750196ce3ccb5a99a4d6c006",
"sha256": "1r8ab79pgrrnzmp49h8rp50c9x8zd0p7bsvzxaphc221nvyfx09j",
"srcDir": "src",
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/c2e1e2e0fa403529750196ce3ccb5a99a4d6c006.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"sys"
],
"path": "/nix/store/syhxsjlsdqfap0hk4qp3s6kayk8cqknd-source",
"rev": "4ef3b624db86e331ba334e705c1aa235d55b05e1",
"sha256": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q",
"srcDir": "src",
"url": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"sys"
],
"path": "/nix/store/syhxsjlsdqfap0hk4qp3s6kayk8cqknd-source",
"rev": "4ef3b624db86e331ba334e705c1aa235d55b05e1",
"sha256": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q",
"srcDir": "src",
"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/6y14ia52kr7jyaa0izx37mlablmq9s65-source",
"rev": "8c8572cd971d1283e6621006b310993c632da247",
"sha256": "1dp166bv9x773jmfqppg5i3v3rilgff013vb11yzwcid9l7s3iy8",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"taps"
],
"path": "/nix/store/6y14ia52kr7jyaa0izx37mlablmq9s65-source",
"rev": "8c8572cd971d1283e6621006b310993c632da247",
"sha256": "1dp166bv9x773jmfqppg5i3v3rilgff013vb11yzwcid9l7s3iy8",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.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": [
"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": [
@ -199,10 +56,10 @@
"nimcrypto"
],
"path": "/nix/store/fkrcpp8lzj2yi21na79xm63xk0ggnqsp-source",
"rev": "f147d30c69bc1c9bcf0e37f7699bcf0fbaab97b5",
"rev": "485f7b3cfa83c1beecc0e31be0e964d697aa74d7",
"sha256": "1h3dzdbc9kacwpi10mj73yjglvn7kbizj1x8qc9099ax091cj5xn",
"srcDir": "",
"url": "https://github.com/cheatfate/nimcrypto/archive/f147d30c69bc1c9bcf0e37f7699bcf0fbaab97b5.tar.gz"
"url": "https://github.com/cheatfate/nimcrypto/archive/485f7b3cfa83c1beecc0e31be0e964d697aa74d7.tar.gz"
},
{
"method": "fetchzip",
@ -215,6 +72,17 @@
"srcDir": "src",
"url": "https://github.com/zevv/npeg/archive/ec0cc6e64ea4c62d2aa382b176a4838474238f8d.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"preserves"
],
"path": "/nix/store/9zl4s2did00725n8ygbp37agvkskdhcx-source",
"rev": "1fee87590940761e288cf9ab3c7270832403b719",
"sha256": "1ny42rwr3yx52zwvkdg4lh54nxaxrmxdj9dlw3qarvvp2grfq4j2",
"srcDir": "src",
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/1fee87590940761e288cf9ab3c7270832403b719.tar.gz"
},
{
"method": "fetchzip",
"packages": [
@ -231,72 +99,39 @@
"packages": [
"sys"
],
"path": "/nix/store/vf9ls2wip6d8xhsi3rjh0dqsqg597i6b-source",
"rev": "c117ee60542f084525f254e6ade590675a6a2ed6",
"sha256": "12qzx2lnh84xqfgypy0pka8nflq0y8n1izfwx8mb4zya5nzawmyf",
"path": "/nix/store/syhxsjlsdqfap0hk4qp3s6kayk8cqknd-source",
"rev": "4ef3b624db86e331ba334e705c1aa235d55b05e1",
"sha256": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q",
"srcDir": "src",
"url": "https://github.com/alaviss/nim-sys/archive/c117ee60542f084525f254e6ade590675a6a2ed6.tar.gz"
"url": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz"
},
{
"date": "2024-04-02T15:38:57+01:00",
"method": "fetchzip",
"packages": [
"taps"
],
"path": "/nix/store/6y14ia52kr7jyaa0izx37mlablmq9s65-source",
"rev": "8c8572cd971d1283e6621006b310993c632da247",
"sha256": "1dp166bv9x773jmfqppg5i3v3rilgff013vb11yzwcid9l7s3iy8",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.tar.gz"
},
{
"date": "2024-05-22T06:09:38+02:00",
"deepClone": false,
"fetchLFS": false,
"fetchSubmodules": true,
"hash": "sha256-iZb9aAgYr4FGkqfIg49QWiCqeizIi047kFhugHiP8o0=",
"hash": "sha256-B3fMwgBpO2Ty8143k9V1cnHXa5K8i1+zN+eF/rBLMe0=",
"leaveDotGit": false,
"method": "git",
"packages": [
"solo5_dispatcher"
],
"path": "/nix/store/sf5dgj2ljvahcm6my7d61ibda51vnrii-solo5_dispatcher",
"rev": "a7a894a96a2221284012800e6fd32923d83d20bd",
"sha256": "13gjixw80vjqj0xlx2y85ixal82sa27q7j57j9383bqq11lgv5l9",
"path": "/nix/store/xqj48v4rqlffl1l94hi02szazj5gla8g-solo5_dispatcher",
"rev": "cc64ef99416b22b12e4a076d33de9e25a163e57d",
"sha256": "1v9i9fqgx1g76yrmz2xwj9mxfwbjfpar6dsyygr68fv9031cqxq7",
"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": [
"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"
},
{
"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"
}
]
}

641
sbom.json Normal file
View File

@ -0,0 +1,641 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"metadata": {
"component": {
"type": "application",
"bom-ref": "pkg:nim/syndicate_utils",
"name": "syndicate_utils",
"description": "Utilites for Syndicated Actors and Synit",
"version": "20240530",
"authors": [
{
"name": "Emery Hemingway"
}
],
"licenses": [
{
"license": {
"id": "Unlicense"
}
}
],
"properties": [
{
"name": "nim:skipExt",
"value": "nim"
},
{
"name": "nim:bin:postgre-actor",
"value": "postgre_actor"
},
{
"name": "nim:bin:xslt-actor",
"value": "xslt_actor"
},
{
"name": "nim:bin:preserve-process-environment",
"value": "preserve_process_environment"
},
{
"name": "nim:bin:mintsturdyref",
"value": "mintsturdyref"
},
{
"name": "nim:bin:esc-printer-actor",
"value": "esc_printer_actor"
},
{
"name": "nim:bin:msg",
"value": "msg"
},
{
"name": "nim:bin:rofi-script-actor",
"value": "rofi_script_actor"
},
{
"name": "nim:bin:syndesizer",
"value": "syndesizer"
},
{
"name": "nim:bin:http-client",
"value": "http_client"
},
{
"name": "nim:bin:mount-actor",
"value": "mount_actor"
},
{
"name": "nim:bin:syndump",
"value": "syndump"
},
{
"name": "nim:srcDir",
"value": "src"
},
{
"name": "nim:backend",
"value": "c"
}
]
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:nim/syndicate",
"name": "syndicate",
"version": "20240522",
"externalReferences": [
{
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/3a4dc1f13392830b587138199643d30fdbec8541.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/aixbd9di4671hm3bg92xsxwhqp4mbs1g-source"
},
{
"name": "nix:fod:rev",
"value": "7ab4611824b676157523f2618e7893d5ac99e4f2"
},
{
"name": "nix:fod:sha256",
"value": "0i53g3578h84gp2lbwx1mddhyh8jrpzdq9h70psqndlgqcg62d59"
},
{
"name": "nix:fod:url",
"value": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/7ab4611824b676157523f2618e7893d5ac99e4f2.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240522"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/preserves",
"name": "preserves",
"version": "20240523",
"externalReferences": [
{
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/1fee87590940761e288cf9ab3c7270832403b719.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/mcwpm48hwm9fwdc0v84cjj773gjzjc0a-source"
},
{
"name": "nix:fod:rev",
"value": "ed065fcc2da71c20a0d5f9972cef2b3261c04727"
},
{
"name": "nix:fod:sha256",
"value": "1jg67izq09mny3n4gpvr9b0b9sbc1gnr9nxj7l43i36sscnnzxr6"
},
{
"name": "nix:fod:url",
"value": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/ed065fcc2da71c20a0d5f9972cef2b3261c04727.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240523"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/sys",
"name": "sys",
"version": "4ef3b624db86e331ba334e705c1aa235d55b05e1",
"externalReferences": [
{
"url": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/ehmry/nim-sys.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/syhxsjlsdqfap0hk4qp3s6kayk8cqknd-source"
},
{
"name": "nix:fod:rev",
"value": "4ef3b624db86e331ba334e705c1aa235d55b05e1"
},
{
"name": "nix:fod:sha256",
"value": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q"
},
{
"name": "nix:fod:url",
"value": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/taps",
"name": "taps",
"version": "20240405",
"externalReferences": [
{
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.sr.ht/~ehmry/nim_taps",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/6y14ia52kr7jyaa0izx37mlablmq9s65-source"
},
{
"name": "nix:fod:rev",
"value": "8c8572cd971d1283e6621006b310993c632da247"
},
{
"name": "nix:fod:sha256",
"value": "1dp166bv9x773jmfqppg5i3v3rilgff013vb11yzwcid9l7s3iy8"
},
{
"name": "nix:fod:url",
"value": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240405"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/nimcrypto",
"name": "nimcrypto",
"version": "traditional-api",
"externalReferences": [
{
"url": "https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/cheatfate/nimcrypto",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/zyr8zwh7vaiycn1s4r8cxwc71f2k5l0h-source"
},
{
"name": "nix:fod:rev",
"value": "602c5d20c69c76137201b5d41f788f72afb95aa8"
},
{
"name": "nix:fod:sha256",
"value": "1dmdmgb6b9m5f8dyxk781nnd61dsk3hdxqks7idk9ncnpj9fng65"
},
{
"name": "nix:fod:url",
"value": "https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "traditional-api"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/npeg",
"name": "npeg",
"version": "1.2.2",
"externalReferences": [
{
"url": "https://github.com/zevv/npeg/archive/ec0cc6e64ea4c62d2aa382b176a4838474238f8d.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/zevv/npeg.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/xpn694ibgipj8xak3j4bky6b3k0vp7hh-source"
},
{
"name": "nix:fod:rev",
"value": "ec0cc6e64ea4c62d2aa382b176a4838474238f8d"
},
{
"name": "nix:fod:sha256",
"value": "1fi9ls3xl20bmv1ikillxywl96i9al6zmmxrbffx448gbrxs86kg"
},
{
"name": "nix:fod:url",
"value": "https://github.com/zevv/npeg/archive/ec0cc6e64ea4c62d2aa382b176a4838474238f8d.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "1.2.2"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/bigints",
"name": "bigints",
"version": "20231006",
"externalReferences": [
{
"url": "https://github.com/ehmry/nim-bigints/archive/86ea14d31eea9275e1408ca34e6bfe9c99989a96.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/ehmry/nim-bigints.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/jvrm392g8adfsgf36prgwkbyd7vh5jsw-source"
},
{
"name": "nix:fod:rev",
"value": "86ea14d31eea9275e1408ca34e6bfe9c99989a96"
},
{
"name": "nix:fod:sha256",
"value": "15pcpmnk1bnw3k8769rjzcpg00nahyrypwbxs88jnwr4aczp99j4"
},
{
"name": "nix:fod:url",
"value": "https://github.com/ehmry/nim-bigints/archive/86ea14d31eea9275e1408ca34e6bfe9c99989a96.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20231006"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/cps",
"name": "cps",
"version": "0.10.4",
"externalReferences": [
{
"url": "https://github.com/nim-works/cps/archive/2a4d771a715ba45cfba3a82fa625ae7ad6591c8b.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/nim-works/cps",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/m9vpcf3dq6z2h1xpi1vlw0ycxp91s5p7-source"
},
{
"name": "nix:fod:rev",
"value": "2a4d771a715ba45cfba3a82fa625ae7ad6591c8b"
},
{
"name": "nix:fod:sha256",
"value": "0c62k5wpq9z9mn8cd4rm8jjc4z0xmnak4piyj5dsfbyj6sbdw2bf"
},
{
"name": "nix:fod:url",
"value": "https://github.com/nim-works/cps/archive/2a4d771a715ba45cfba3a82fa625ae7ad6591c8b.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "0.10.4"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/stew",
"name": "stew",
"version": "3c91b8694e15137a81ec7db37c6c58194ec94a6a",
"externalReferences": [
{
"url": "https://github.com/status-im/nim-stew/archive/3c91b8694e15137a81ec7db37c6c58194ec94a6a.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/status-im/nim-stew",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/mqg8qzsbcc8xqabq2yzvlhvcyqypk72c-source"
},
{
"name": "nix:fod:rev",
"value": "3c91b8694e15137a81ec7db37c6c58194ec94a6a"
},
{
"name": "nix:fod:sha256",
"value": "17lfhfxp5nxvld78xa83p258y80ks5jb4n53152cdr57xk86y07w"
},
{
"name": "nix:fod:url",
"value": "https://github.com/status-im/nim-stew/archive/3c91b8694e15137a81ec7db37c6c58194ec94a6a.tar.gz"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/getdns",
"name": "getdns",
"version": "20230806",
"externalReferences": [
{
"url": "https://git.sr.ht/~ehmry/getdns-nim/archive/e4ae0992ed7c5540e6d498f3074d06c8f454a0b6.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.sr.ht/~ehmry/getdns-nim",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/j8i20k9aarzppg4p234449140nnnaycq-source"
},
{
"name": "nix:fod:rev",
"value": "e4ae0992ed7c5540e6d498f3074d06c8f454a0b6"
},
{
"name": "nix:fod:sha256",
"value": "1dp53gndr6d9s9601dd5ipkiq94j53hlx46mxv8gpr8nd98bqysg"
},
{
"name": "nix:fod:url",
"value": "https://git.sr.ht/~ehmry/getdns-nim/archive/e4ae0992ed7c5540e6d498f3074d06c8f454a0b6.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20230806"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/solo5_dispatcher",
"name": "solo5_dispatcher",
"version": "20240522",
"externalReferences": [
{
"url": "https://git.sr.ht/~ehmry/solo5_dispatcher/archive/cc64ef99416b22b12e4a076d33de9e25a163e57d.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.sr.ht/~ehmry/solo5_dispatcher",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/4jj467pg4hs6warhksb8nsxn9ykz8c7c-source"
},
{
"name": "nix:fod:rev",
"value": "cc64ef99416b22b12e4a076d33de9e25a163e57d"
},
{
"name": "nix:fod:sha256",
"value": "1v9i9fqgx1g76yrmz2xwj9mxfwbjfpar6dsyygr68fv9031cqxq7"
},
{
"name": "nix:fod:url",
"value": "https://git.sr.ht/~ehmry/solo5_dispatcher/archive/cc64ef99416b22b12e4a076d33de9e25a163e57d.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240522"
},
{
"name": "nix:fod:srcDir",
"value": "pkg"
}
]
}
],
"dependencies": [
{
"ref": "pkg:nim/syndicate_utils",
"dependsOn": [
"pkg:nim/syndicate"
]
},
{
"ref": "pkg:nim/syndicate",
"dependsOn": [
"pkg:nim/nimcrypto",
"pkg:nim/preserves",
"pkg:nim/sys",
"pkg:nim/taps"
]
},
{
"ref": "pkg:nim/preserves",
"dependsOn": [
"pkg:nim/npeg",
"pkg:nim/bigints"
]
},
{
"ref": "pkg:nim/sys",
"dependsOn": [
"pkg:nim/cps",
"pkg:nim/stew"
]
},
{
"ref": "pkg:nim/taps",
"dependsOn": [
"pkg:nim/getdns",
"pkg:nim/sys",
"pkg:nim/cps",
"pkg:nim/solo5_dispatcher"
]
},
{
"ref": "pkg:nim/nimcrypto",
"dependsOn": []
},
{
"ref": "pkg:nim/npeg",
"dependsOn": []
},
{
"ref": "pkg:nim/bigints",
"dependsOn": []
},
{
"ref": "pkg:nim/cps",
"dependsOn": []
},
{
"ref": "pkg:nim/stew",
"dependsOn": []
},
{
"ref": "pkg:nim/getdns",
"dependsOn": []
},
{
"ref": "pkg:nim/solo5_dispatcher",
"dependsOn": [
"pkg:nim/cps"
]
}
]
}

View File

@ -1,11 +0,0 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.buildNimPackage {
name = "syndicate_utils";
propagatedNativeBuildInputs =
builtins.attrValues { inherit (pkgs) pkg-config solo5; };
propagatedBuildInputs = builtins.attrValues {
inherit (pkgs) getdns postgresql solo5 sqlite libxml2 libxslt;
};
lockFile = ./lock.json;
}

View File

@ -2,4 +2,7 @@ version 1 .
# When asserted the actor reponds to @target rows as records
# of the given label and row columns as record fields.
Query = <query @statement string @target #:any> .
Query = <query @statement [any ...] @target #:any> .
# When a query fails this is asserted instead.
SqlError = <sql-error @msg string @context string>.

84
src/esc_printer_actor.nim Normal file
View File

@ -0,0 +1,84 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
## ESC/P printer control actor.
import
std/[cmdline, oserrors, posix, sets],
preserves, preserves/sugar,
syndicate, syndicate/relays,
./private/esc_p
proc echo(args: varargs[string, `$`]) {.used.} =
stderr.writeLine(args)
type
HandleSet = HashSet[Handle]
Printer = ref object of Entity
device: cint
boldHandles, italicHandles, superscriptHandles, subscriptHandles: HandleSet
proc write(printer: Printer; s: string) {.inline.} =
if posix.write(printer.device, s[0].addr, s.len) < 0:
osLastError().osErrorMsg().quit()
proc writeLine(printer: Printer; s: string) {.inline.} =
printer.write(s)
printer.write("\r\n")
method message(printer: Printer; t: Turn; a: AssertionRef) =
if a.value.isString:
printer.write(a.value.string)
# TODO: unicode?
# TODO: line breaks?
proc assert(printer: Printer; handles: var HandleSet; ctrl: string; h: Handle) =
if handles.len == 0: printer.write(ctrl)
handles.incl h
proc retract(printer: Printer; handles: var HandleSet; ctrl: string; h: Handle) =
handles.excl h
if handles.len == 0: printer.write(ctrl)
method publish(printer: Printer; t: Turn; a: AssertionRef; h: Handle) =
if a.value.isRecord("bold"):
printer.assert(printer.boldHandles, SelectBoldFont, h)
elif a.value.isRecord("italic"):
printer.assert(printer.italicHandles, SelectItalicFont, h)
elif a.value.isRecord("superscript"):
printer.assert(printer.superscriptHandles, SelectSuperScript, h)
elif a.value.isRecord("subscript"):
printer.assert(printer.subscriptHandles, SelectSubScript, h)
method retract(printer: Printer; t: Turn; h: Handle) =
if printer.boldHandles.contains h:
printer.retract(printer.boldHandles, CancelBoldFont, h)
elif printer.italicHandles.contains h:
printer.retract(printer.italicHandles, CanceItalicFont, h)
elif printer.superscriptHandles.contains h:
printer.retract(printer.superscriptHandles, CancelAltScript, h)
elif printer.subscriptHandles.contains h:
printer.retract(printer.subscriptHandles, CancelAltScript, h)
proc openPrinter(turn: Turn; devicePath: string): Printer =
new result
result.facet = turn.facet
result.device = posix.open(devicePath, O_WRONLY, 0)
result.write(InitializePrinter)
proc main =
let devicePath = paramStr(1)
runActor(devicePath) do (turn: Turn):
let printer = turn.newCap openPrinter(turn, devicePath)
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
publish(turn, ds, initRecord(
toSymbol"printer", printer.embed, %devicePath))
main()

91
src/http_client.nim Normal file
View File

@ -0,0 +1,91 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
# TODO: write a TAPS HTTP client. Figure out how to externalise TLS.
import
std/[httpclient, options, streams, strutils, tables, uri],
pkg/taps,
pkg/preserves,
pkg/syndicate, pkg/syndicate/protocols/http,
./schema/config
proc url(req: HttpRequest): Uri =
result.scheme = if req.port == 80: "http" else: "https"
result.hostname = req.host.present
result.port = $req.port
for i, p in req.path:
if 0 < i: result.path.add '/'
result.path.add p.encodeUrl
for key, vals in req.query:
if result.query.len > 0:
result.query.add '&'
result.query.add key.string.encodeUrl
for i, val in vals:
if i == 0: result.query.add '='
elif i < vals.high: result.query.add ','
result.query.add val.string.encodeUrl
proc bodyString(req: HttpRequest): string =
if req.body.orKind == RequestBodyKind.present:
return cast[string](req.body.present)
proc spawnHttpClient*(turn: Turn; root: Cap): Actor {.discardable.} =
during(turn, root, ?:HttpClientArguments) do (ds: Cap):
spawn("http-client", turn) do (turn: Turn):
during(turn, ds, HttpContext.grabType) do (ctx: HttpContext):
let peer = ctx.res.unembed(Cap).get
var client = newHttpClient()
try:
var
headers = newHttpHeaders()
contentType = ""
for key, val in ctx.req.headers:
if key == Symbol"Content-Type":
contentType = val
client.headers[key.string] = val
let stdRes = client.request(
ctx.req.url,
ctx.req.method.string.toUpper,
ctx.req.bodyString, headers
)
var resp = HttpResponse(orKind: HttpResponseKind.status)
resp.status.code = stdRes.status[0 .. 2].parseInt
resp.status.message = stdRes.status[3 .. ^1]
message(turn, peer, resp)
resp = HttpResponse(orKind: HttpResponseKind.header)
for key, val in stdRes.headers:
if key == "Content-Type":
contentType = val
resp.header.name = key.Symbol
resp.header.value = val
message(turn, peer, resp)
case contentType
of "application/json", "text/preserves":
message(turn, peer,
initRecord("done", stdRes.bodyStream.readAll.parsePreserves))
of "application/preserves":
message(turn, peer,
initRecord("done", stdRes.bodyStream.decodePreserves))
else:
resp = HttpResponse(orKind: HttpResponseKind.done)
resp.done.chunk.string = stdRes.bodyStream.readAll()
message(turn, peer, resp)
except CatchableError as err:
var resp = HttpResponse(orKind: HttpResponseKind.status)
resp.status.code = 400
resp.status.message = "Internal client error"
message(turn, peer, resp)
resp = HttpResponse(orKind: HttpResponseKind.done)
resp.done.chunk.string = err.msg
message(turn, peer, resp)
client.close()
do:
client.close()
when isMainModule:
import syndicate/relays
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnHttpClient(turn, ds)

1
src/http_client.nim.cfg Normal file
View File

@ -0,0 +1 @@
define:ssl

View File

@ -7,7 +7,7 @@ when not defined(linux):
{.error: "this component only tested for Linux".}
import std/oserrors
import preserves
import preserves, preserves/sugar
import syndicate
import ./schema/mountpoints
@ -20,11 +20,14 @@ proc mount(source, target, fsType: cstring; flags: culong; data: pointer): cint
proc umount(target: cstring): cint {.importc, header: "<sys/mount.h>".}
## `umount(2)`
proc spawnMountActor*(turn: var Turn; ds: Cap): Actor {.discardable.} =
spawnActor(turn, "mount_actor") do (turn: var Turn):
proc spawnMountActor*(turn: Turn; ds: Cap): Actor {.discardable.} =
spawnActor(turn, "mount_actor") do (turn: Turn):
let
targetPat = ?Observe(pattern: !Mountpoint) ?? { 1: grabLit() }
sourcePat = ?Observe(pattern: !Mountpoint) ?? { 0: grabLit(), 2: grabLit() }
targetPat = observePattern(!Mountpoint, { @[%1]: grabLit() })
sourcePat = observePattern(!Mountpoint, {
@[%0]: grabLit(),
@[%2]: grabLit(),
})
during(turn, ds, ?:BootArgs) do (ds: Cap):
during(turn, ds, targetPat) do (target: string):
during(turn, ds, sourcePat) do (source: string, fsType: string):
@ -45,6 +48,6 @@ proc spawnMountActor*(turn: var Turn; ds: Cap): Actor {.discardable.} =
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
discard spawnMountActor(turn, ds)

View File

@ -6,11 +6,11 @@ import preserves, syndicate, syndicate/relays
setControlCHook(proc () {.noconv.} = quit())
runActor("msg") do (turn: var Turn):
runActor("msg") do (turn: Turn):
let
data = map(commandLineParams(), parsePreserves)
cmd = paramStr(0).extractFilename.normalize
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
case cmd
of "assert":
for e in data:
@ -18,5 +18,5 @@ runActor("msg") do (turn: var Turn):
else: # "msg"
for e in data:
message(turn, ds, e)
sync(turn, ds) do (turn: var Turn):
sync(turn, ds) do (turn: Turn):
stopActor(turn)

View File

@ -87,8 +87,26 @@ proc splitParams(params: StringPairs): (cstringArray, cstringArray) =
for i, _ in params: strings[i] = params[i][1]
result[1] = allocCStringArray(strings)
proc spawnPostgreActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawn("postgre", turn) do (turn: var Turn):
proc renderSql(tokens: openarray[Value]): string =
for token in tokens:
if result.len > 0: result.add ' '
case token.kind
of pkSymbol:
result.add token.symbol.string
of pkString:
result.add '\''
result.add token.string
result.add '\''
of pkFloat, pkRegister, pkBigInt:
result.add $token
of pkBoolean:
if token.bool: result.add '1'
else: result.add '0'
else:
return ""
proc spawnPostgreActor*(turn: Turn; root: Cap): Actor {.discardable.} =
spawn("postgre", turn) do (turn: Turn):
during(turn, root, ?:PostgreArguments) do (params: StringPairs, ds: Cap):
var
conn: PGconn
@ -102,11 +120,14 @@ proc spawnPostgreActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
statusHandle = publish(turn, ds,
initRecord("status", toSymbol($status), msg.toPreserves))
if status == CONNECTION_OK:
during(turn, ds, ?:Query) do (statement: string, target: Cap):
var res = PQexec(conn, statement)
var st = PQresultStatus(res)
discard publish(turn, ds, toRecord(
"error", statement, toSymbol($PQresStatus(st)), $PQresultErrorMessage(res)))
during(turn, ds, ?:Query) do (statement: seq[Value], target: Cap):
var text = renderSql statement
if text == "":
discard publish(turn, ds, SqlError(msg: "invalid statement", context: $statement))
else:
var
res = PQexec(conn, text)
st = PQresultStatus(res)
if st == PGRES_TUPLES_OK or st == PGRES_SINGLE_TUPLE:
let tuples = PQntuples(res)
let fields = PQnfields(res)
@ -116,6 +137,11 @@ proc spawnPostgreActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
for f in 0..<fields:
tupl[f] = toPreserves($PQgetvalue(res, r, f))
discard publish(turn, target, tupl)
else:
discard publish(turn, ds, SqlError(
msg: $PQresStatus(st),
context: $PQresultErrorMessage(res),
))
PQclear(res)
else:
stderr.writeLine "refusing to do anything when status is ", status
@ -127,6 +153,6 @@ proc spawnPostgreActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnPostgreActor(turn, ds)

11
src/private/esc_p.nim Normal file
View File

@ -0,0 +1,11 @@
const
ESC* = "\x1b"
InitializePrinter* = ESC & "@"
CancelLine* = ESC & "\x18"
SelectBoldFont* = ESC & "E"
CancelBoldFont* = ESC & "F"
SelectItalicFont* = ESC & "4"
CanceItalicFont* = ESC & "5"
SelectSuperScript* = ESC & "S0"
SelectSubScript* = ESC & "S1"
CancelAltScript* = ESC & "T"

View File

@ -10,8 +10,8 @@ import ./schema/rofi
if getEnv("ROFI_OUTSIDE") == "":
quit("run this program in rofi")
runActor("rofi_script_actor") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("rofi_script_actor") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
case paramCount()
of 0:
let pat = ?:Options

View File

@ -10,6 +10,12 @@ type
WebsocketArguments* {.preservesRecord: "websocket".} = object
`field0`*: WebsocketArgumentsField0
HttpClientArgumentsField0* {.preservesDictionary.} = object
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
HttpClientArguments* {.preservesRecord: "http-client".} = object
`field0`*: HttpClientArgumentsField0
JsonTranslatorArgumentsField0* {.preservesDictionary.} = object
`argv`*: seq[string]
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
@ -117,7 +123,8 @@ type
`host`*: string
`port`*: BiggestInt
proc `$`*(x: WebsocketArguments | JsonTranslatorArguments | SocketAddress |
proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments |
SocketAddress |
Base64DecoderArguments |
JsonTranslatorConnected |
JsonSocketTranslatorArguments |
@ -136,7 +143,9 @@ proc `$`*(x: WebsocketArguments | JsonTranslatorArguments | SocketAddress |
Tcp): string =
`$`(toPreserves(x))
proc encode*(x: WebsocketArguments | JsonTranslatorArguments | SocketAddress |
proc encode*(x: WebsocketArguments | HttpClientArguments |
JsonTranslatorArguments |
SocketAddress |
Base64DecoderArguments |
JsonTranslatorConnected |
JsonSocketTranslatorArguments |

View File

@ -4,11 +4,15 @@ import
type
Query* {.preservesRecord: "query".} = object
`statement`*: string
`statement`*: seq[Value]
`target`* {.preservesEmbedded.}: Value
proc `$`*(x: Query): string =
SqlError* {.preservesRecord: "sql-error".} = object
`msg`*: string
`context`*: string
proc `$`*(x: Query | SqlError): string =
`$`(toPreserves(x))
proc encode*(x: Query): seq[byte] =
proc encode*(x: Query | SqlError): seq[byte] =
encode(toPreserves(x))

View File

@ -54,8 +54,19 @@ proc finalize(stmt: Stmt): cint {.importSqlite3.}
doAssert libversion_number() == SQLITE_VERSION_NUMBER
proc logError(db: Sqlite3; context: string) =
writeLine(stderr, errmsg(db), ": ", context)
proc assertError(facet: Facet; cap: Cap; db: Sqlite3; context: string) =
run(facet) do (turn: Turn):
publish(turn, cap, SqlError(
msg: $errmsg(db),
context: context,
))
proc assertError(facet: Facet; cap: Cap; msg, context: string) =
run(facet) do (turn: Turn):
publish(turn, cap, SqlError(
msg: msg,
context: context,
))
proc extractValue(stmt: Stmt; col: cint): Value =
case column_type(stmt, col)
@ -78,18 +89,45 @@ proc extractTuple(stmt: Stmt; arity: cint): Value =
result = initSequence(arity)
for col in 0..<arity: result[col] = extractValue(stmt, col)
proc spawnSqliteActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawn("sqlite-actor", turn) do (turn: var Turn):
proc renderSql(tokens: openarray[Value]): string =
for token in tokens:
if result.len > 0: result.add ' '
case token.kind
of pkSymbol:
result.add token.symbol.string
of pkString:
result.add '\''
result.add token.string
result.add '\''
of pkFloat, pkRegister, pkBigInt:
result.add $token
of pkBoolean:
if token.bool: result.add '1'
else: result.add '0'
else:
return ""
proc spawnSqliteActor*(turn: Turn; root: Cap): Actor {.discardable.} =
spawn("sqlite-actor", turn) do (turn: Turn):
during(turn, root, ?:SqliteArguments) do (path: string, ds: Cap):
linkActor(turn, path) do (turn: Turn):
let facet = turn.facet
stderr.writeLine("opening SQLite database ", path)
var db: Sqlite3
if open_v2(path, addr db, SQLITE_OPEN_READONLY, nil) != SQLITE_OK:
logError(db, path)
assertError(facet, ds, db, path)
else:
during(turn, ds, ?:Query) do (statement: string, target: Cap):
var stmt: Stmt
if prepare_v2(db, statement, statement.len.cint, addr stmt, nil) != SQLITE_OK:
logError(db, statement)
turn.onStop do (turn: Turn):
close(db)
stderr.writeLine("closed SQLite database ", path)
during(turn, ds, ?:Query) do (statement: seq[Value], target: Cap):
var
stmt: Stmt
text = renderSql statement
if text == "":
assertError(facet, target, "invalid statement", $statement)
elif prepare_v2(db, text, text.len.cint, addr stmt, nil) != SQLITE_OK:
assertError(facet, target, db, text)
else:
try:
let arity = column_count(stmt)
@ -100,15 +138,12 @@ proc spawnSqliteActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
res = step(stmt)
assert res != 100
if res != SQLITE_DONE:
logError(db, statement)
assertError(facet, target, db, text)
finally:
if finalize(stmt) != SQLITE_OK: logError(db, statement)
do:
close(db)
stderr.writeLine("closed SQLite database ", path)
if finalize(stmt) != SQLITE_OK: assertError(facet, target, db, text)
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnSqliteActor(turn, ds)

View File

@ -15,8 +15,8 @@ import ./syndesizer/[
pulses,
xml_translator]
runActor("syndesizer") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("syndesizer") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
discard spawnTimerDriver(turn, ds)
discard spawnBase64Decoder(turn, ds)
discard spawnCacheActor(turn, ds)

View File

@ -1,41 +1,40 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[base64, os]
import pkg/hashlib/misc/blake2
import preserves, syndicate
import ../schema/config
import ../schema/base64 as schema
import
std/[base64, os],
pkg/nimcrypto/blake2,
preserves, preserves/sugar, syndicate,
../schema/config,
../schema/base64 as schema
export Base64DecoderArguments
export schema
proc spawnBase64Decoder*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "base64-decoder") do (turn: var Turn):
proc spawnBase64Decoder*(turn: Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "base64-decoder") do (turn: Turn):
let tmpDir = getTempDir()
during(turn, root, ?:Base64DecoderArguments) do (ds: Cap):
let decTextPat = ?Observe(pattern: !Base64Text) ?? { 0: grabLit() }
let decTextPat = observePattern(!Base64Text, { @[%0]: grabLit() })
during(turn, ds, decTextPat) do (txt: string):
discard publish(turn, ds, Base64Text(
txt: txt,
bin: cast[seq[byte]](decode(txt)),
))
let encTextPat = ?Observe(pattern: !Base64Text) ?? { 1: grabLit() }
let encTextPat = observePattern(!Base64Text, { @[%1]: grabLit() })
during(turn, ds, encTextPat) do (bin: seq[byte]):
discard publish(turn, ds, Base64Text(
txt: encode(bin),
bin: bin,
))
let decFilePat = ?Observe(pattern: !Base64File) ?? { 0: grabLit() }
let decFilePat = observePattern( !Base64File, { @[%0]: grabLit() })
during(turn, ds, decFilePat) do (txt: string):
var bin = decode(txt)
var ctx = init[BLAKE2B_512]()
ctx.update(bin)
let
digest = $ctx.final()
var
bin = decode(txt)
digest = $blake2_256.digest(bin)
path = tmpDir / digest
writeFile(path, bin)
discard publish(turn, ds, Base64File(
@ -46,6 +45,6 @@ proc spawnBase64Decoder*(turn: var Turn; root: Cap): Actor {.discardable.} =
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnBase64Decoder(turn, ds)

View File

@ -18,9 +18,9 @@ type CacheEntity {.final.} = ref object of Entity
pattern: Pattern
lifetime: float64
method publish(cache: CacheEntity; turn: var Turn; ass: AssertionRef; h: Handle) =
method publish(cache: CacheEntity; turn: Turn; ass: AssertionRef; h: Handle) =
## Re-assert pattern captures in a sub-facet.
discard inFacet(turn) do (turn: var Turn):
discard inFacet(turn) do (turn: Turn):
# TODO: a seperate facet for every assertion, too much?
var ass = depattern(cache.pattern, ass.value.sequence)
# Build an assertion with what he have of the pattern and capture.
@ -30,12 +30,12 @@ method publish(cache: CacheEntity; turn: var Turn; ass: AssertionRef; h: Handle)
stop(turn) # end this facet
proc isObserve(pat: Pattern): bool =
pat.orKind == PatternKind.DCompound and
pat.dcompound.orKind == DCompoundKind.rec and
pat.dcompound.rec.label.isSymbol"Observe"
pat.orKind == PatternKind.group and
pat.group.type.orKind == GroupTypeKind.rec and
pat.group.type.rec.label.isSymbol"Observe"
proc spawnCacheActor*(turn: var Turn; root: Cap): Actor =
spawnActor(turn, "cache_actor") do (turn: var Turn):
proc spawnCacheActor*(turn: Turn; root: Cap): Actor =
spawnActor(turn, "cache_actor") do (turn: Turn):
during(turn, root, ?:CacheArguments) do (ds: Cap, lifetime: float64):
onPublish(turn, ds, ?:Observe) do (pat: Pattern, obs: Cap):
var cache: CacheEntity
@ -52,7 +52,7 @@ proc spawnCacheActor*(turn: var Turn; root: Cap): Actor =
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
discard spawnTimerDriver(turn, ds)
discard spawnCacheActor(turn, ds)

View File

@ -2,15 +2,15 @@
# SPDX-License-Identifier: Unlicense
import std/[dirs, os, paths]
import preserves
import preserves, preserves/sugar
import syndicate
import ../schema/[assertions, config]
proc spawnFileSystemUsageActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawn("file-system-usage", turn) do (turn: var Turn):
proc spawnFileSystemUsageActor*(turn: Turn; root: Cap): Actor {.discardable.} =
spawn("file-system-usage", turn) do (turn: Turn):
during(turn, root, ?:FileSystemUsageArguments) do (ds: Cap):
var pat = ?Observe(pattern: !FileSystemUsage) ?? { 0: grab() }
let pat = observePattern(!FileSystemUsage, { @[%0]: grab() })
during(turn, ds, pat) do (lit: Literal[string]):
var ass = FileSystemUsage(path: lit.value)
if fileExists(ass.path): ass.size = getFileSize(ass.path)
@ -23,6 +23,6 @@ proc spawnFileSystemUsageActor*(turn: var Turn; root: Cap): Actor {.discardable.
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
discard spawnFileSystemUsageActor(turn, ds)

View File

@ -8,7 +8,7 @@ import pkg/syndicate/drivers/http_driver
import pkg/taps
import ../schema/config
proc spawnHttpDriver*(turn: var Turn; ds: Cap): Actor {.discardable.}=
proc spawnHttpDriver*(turn: Turn; ds: Cap): Actor {.discardable.}=
http_driver.spawnHttpDriver(turn, ds)
during(turn, ds, ?:HttpDriverArguments) do (ds: Cap):
http_driver.spawnHttpDriver(turn, ds)
@ -30,13 +30,13 @@ when isMainModule:
return
quit("failed to parse command line for route to Syndicate gatekeeper")
runActor("main") do (turn: var Turn):
runActor("main") do (turn: Turn):
let ds = newDataspace(turn)
spawnRelays(turn, ds)
resolve(turn, ds, envRoute(), spawnHttpDriver)
else:
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnHttpDriver(turn, ds)

View File

@ -14,9 +14,9 @@ template translateSocketBody {.dirty.} =
dec = newBufferedDecoder(0)
buf = new string #TODO: get a pointer into the decoder
alive = true
proc kill(turn: var Turn) =
proc kill(turn: Turn) =
alive = false
proc setup(turn: var Turn) =
proc setup(turn: Turn) =
# Closure, not CPS.
onMessage(turn, ds, ?:SendJson) do (data: JsonNode):
if alive:
@ -38,7 +38,7 @@ template translateSocketBody {.dirty.} =
dec.feed(buf[])
var data = dec.parse()
if data.isSome:
proc send(turn: var Turn) =
proc send(turn: Turn) =
# Closure, not CPS.
message(turn, ds, initRecord("recv", data.get))
run(facet, send)
@ -59,19 +59,19 @@ proc translateSocket(facet: Facet; ds: Cap; sa: UnixAddress) {.asyncio.} =
socket[] = conn
translateSocketBody()
proc spawnJsonSocketTranslator*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "json-socket-translator") do (turn: var Turn):
proc spawnJsonSocketTranslator*(turn: Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "json-socket-translator") do (turn: Turn):
during(turn, root, ?:JsonSocketTranslatorArguments) do (ds: Cap, sa: TcpAddress):
linkActor(turn, "json-socket-translator") do (turn: var Turn):
linkActor(turn, "json-socket-translator") do (turn: Turn):
discard trampoline:
whelp translateSocket(turn.facet, ds, sa)
during(turn, root, ?:JsonSocketTranslatorArguments) do (ds: Cap, sa: UnixAddress):
linkActor(turn, "json-socket-translator") do (turn: var Turn):
linkActor(turn, "json-socket-translator") do (turn: Turn):
discard trampoline:
whelp translateSocket(turn.facet, ds, sa)
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnJsonSocketTranslator(turn, ds)

View File

@ -19,8 +19,8 @@ proc runChild(params: seq[string]): string =
if result == "":
stderr.writeLine "no ouput"
proc spawnJsonStdioTranslator*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "json-stdio-translator") do (turn: var Turn):
proc spawnJsonStdioTranslator*(turn: Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "json-stdio-translator") do (turn: Turn):
during(turn, root, ?:JsonTranslatorArguments) do (argv: seq[string], ds: Cap):
var js = parseJson(runChild(argv))
message(turn, ds, RecvJson(data: js))
@ -28,6 +28,6 @@ proc spawnJsonStdioTranslator*(turn: var Turn; root: Cap): Actor {.discardable.}
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnJsonStdioTranslator(turn, ds)

View File

@ -2,7 +2,8 @@
# SPDX-License-Identifier: Unlicense
import std/[options, tables, times]
import preserves, syndicate, syndicate/drivers/timers
import preserves, preserves/sugar
import syndicate, syndicate/drivers/timers
import ../schema/[assertions, config]
@ -16,7 +17,7 @@ type PulseEntity {.final.} = ref object of Entity
observePattern: Pattern
observing: bool
proc schedule(turn: var Turn; pulse: PulseEntity) =
proc schedule(turn: Turn; pulse: PulseEntity) =
## Schedule the next pulse.
## The next pulse will be schedule using the current time as
## reference point and not the moment of the previous pulse.
@ -26,7 +27,7 @@ proc schedule(turn: var Turn; pulse: PulseEntity) =
observer: pulse.self,
))
method publish(pulse: PulseEntity; turn: var Turn; ass: AssertionRef; h: Handle) =
method publish(pulse: PulseEntity; turn: Turn; ass: AssertionRef; h: Handle) =
## Publish observers in reponse to <later-than …> assertions.
pulse.timers.target.retract(turn, pulse.timerHandle)
schedule(turn, pulse)
@ -35,7 +36,7 @@ method publish(pulse: PulseEntity; turn: var Turn; ass: AssertionRef; h: Handle)
pulse.target.publish(turn, a, h)
pulse.target.sync(turn, pulse.self)
method message(pulse: PulseEntity; turn: var Turn; v: AssertionRef) =
method message(pulse: PulseEntity; turn: Turn; v: AssertionRef) =
## Retract observers in response to a sync message.
pulse.observing = false
for h in pulse.observers.keys:
@ -45,7 +46,7 @@ type ProxyEntity {.final.} = ref object of Entity
## A proxy `Entity` that diverts observers to a `PulseEntity`.
pulse: PulseEntity
method publish(proxy: ProxyEntity; turn: var Turn; ass: AssertionRef; h: Handle) =
method publish(proxy: ProxyEntity; turn: Turn; ass: AssertionRef; h: Handle) =
## Proxy assertions that are not observations.
if proxy.pulse.observePattern.matches ass.value:
if proxy.pulse.observers.len == 0:
@ -54,7 +55,7 @@ method publish(proxy: ProxyEntity; turn: var Turn; ass: AssertionRef; h: Handle)
else:
proxy.pulse.target.publish(turn, ass, h)
method retract(proxy: ProxyEntity; turn: var Turn; h: Handle) =
method retract(proxy: ProxyEntity; turn: Turn; h: Handle) =
## Retract proxied assertions.
var obs: AssertionRef
if proxy.pulse.observers.pop(h, obs):
@ -65,15 +66,15 @@ method retract(proxy: ProxyEntity; turn: var Turn; h: Handle) =
else:
proxy.pulse.target.retract(turn, h)
method message(proxy: ProxyEntity; turn: var Turn; v: AssertionRef) =
method message(proxy: ProxyEntity; turn: Turn; v: AssertionRef) =
## Proxy mesages.
proxy.pulse.target.message(turn, v)
method sync(proxy: ProxyEntity; turn: var Turn; peer: Cap) =
method sync(proxy: ProxyEntity; turn: Turn; peer: Cap) =
## Proxy sync.
proxy.pulse.target.sync(turn, peer)
proc newProxyEntity(turn: var Turn; timers, ds: Cap; period: float): ProxyEntity =
proc newProxyEntity(turn: Turn; timers, ds: Cap; period: float): ProxyEntity =
new result
result.pulse = PulseEntity(
target: ds.target,
@ -83,11 +84,11 @@ proc newProxyEntity(turn: var Turn; timers, ds: Cap; period: float): ProxyEntity
)
result.pulse.self = newCap(turn, result.pulse)
proc spawnPulseActor*(turn: var Turn; root: Cap): Actor =
proc spawnPulseActor*(turn: Turn; root: Cap): Actor =
## Spawn an actor that retracts and re-asserts observers on
## a timed pulse. Requires a timer service on the `root` capability.
spawnActor(turn, "pulse") do (turn: var Turn):
let grabPeriod = ?Observe(pattern: !Pulse) ?? { 0: grab() }
spawnActor(turn, "pulse") do (turn: Turn):
let grabPeriod = observePattern(!Pulse, { @[%0]: grab() })
during(turn, root, ?:PulseArguments) do (ds: Cap):
during(turn, ds, grabPeriod) do (lit: Literal[float]):
if lit.value < 0.000_1:
@ -99,6 +100,6 @@ proc spawnPulseActor*(turn: var Turn; root: Cap): Actor =
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
discard spawnPulseActor(turn, ds)

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: Unlicense
import std/[options, parsexml, xmlparser, xmltree]
import preserves, preserves/xmlhooks
import preserves, preserves/sugar, preserves/xmlhooks
import syndicate
import ../schema/[assertions, config]
@ -17,17 +17,18 @@ proc translatePreserves(pr: Value): XmlTranslation {.gcsafe.} =
var xn = result.pr.preservesTo(XmlNode)
if xn.isSome: result.xml = $get(xn)
proc spawnXmlTranslator*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "xml-translator") do (turn: var Turn):
proc spawnXmlTranslator*(turn: Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "xml-translator") do (turn: Turn):
during(turn, root, ?:XmlTranslatorArguments) do (ds: Cap):
let obsPat = ?Observe(pattern: !XmlTranslation)
during(turn, ds, obsPat ?? {0: grab()}) do (xs: Literal[string]):
let xmlPat = observePattern(!XmlTranslation, {@[%0]:grab()})
during(turn, ds, xmlPat) do (xs: Literal[string]):
publish(turn, ds, translateXml(xs.value))
during(turn, ds, obsPat ?? {1: grab()}) do (pr: Literal[Value]):
let prPat = observePattern(!XmlTranslation, {@[%1]:grab()})
during(turn, ds, prPat) do (pr: Literal[Value]):
publish(turn, ds, translatePreserves(pr.value))
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnXmlTranslator(turn, ds)

View File

@ -8,7 +8,7 @@ proc parsePattern(pr: Value): Pattern =
let
dropSigil = initRecord("lit", "_".toSymbol)
grabSigil = initRecord("lit", "?".toSymbol)
var pr = grab(pr).toPreserves
var pr = drop(pr).toPreserves
apply(pr) do (pr: var Value):
if pr == dropSigil:
pr = initRecord("_")
@ -36,19 +36,19 @@ proc toLine(values: seq[Value]; prefix: char): string =
add(result, $v)
add(result, '\n')
method publish(dump: DumpEntity; turn: var Turn; ass: AssertionRef; h: Handle) =
method publish(dump: DumpEntity; turn: Turn; ass: AssertionRef; h: Handle) =
var values = ass.value.sequence
stdout.write(values.toLine('+'))
stdout.flushFile()
dump.assertions[h] = values
method retract(dump: DumpEntity; turn: var Turn; h: Handle) =
method retract(dump: DumpEntity; turn: Turn; h: Handle) =
var values: seq[Value]
if dump.assertions.pop(h, values):
stdout.write(values.toLine('-'))
stdout.flushFile()
method message*(dump: DumpEntity; turn: var Turn; ass: AssertionRef) =
method message*(dump: DumpEntity; turn: Turn; ass: AssertionRef) =
stdout.write(ass.value.sequence.toLine('!'))
stdout.flushFile()
@ -60,8 +60,8 @@ proc main =
let
patterns = inputPatterns()
entity = DumpEntity()
runActor("syndex_card") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("syndex_card") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
for pat in patterns:
discard observe(turn, ds, pat, entity)

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: Unlicense
import std/[os, strutils]
import preserves, syndicate
import preserves, preserves/sugar, syndicate
import ./schema/[assertions, config]
{.passC: staticExec("pkg-config --cflags libxslt").}
@ -173,11 +173,11 @@ proc toPreservesHook*(xn: xmlNodePtr): Value =
preserveSiblings(items, xn)
items[0]
proc spawnXsltActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "xslt") do (turn: var Turn):
proc spawnXsltActor*(turn: Turn; root: Cap): Actor {.discardable.} =
spawnActor(turn, "xslt") do (turn: Turn):
initLibXml()
during(turn, root, ?:XsltArguments) do (ds: Cap):
let sheetsPat = ?Observe(pattern: !XsltTransform) ?? {0: grab(), 1: grab()}
let sheetsPat = observePattern(!XsltTransform, {@[%0]: grab(), @[%1]: grab()})
during(turn, ds, sheetsPat) do (stylesheet: Literal[string], input: Literal[string]):
let cur = loadStylesheet(stylesheet.value)
if cur.isNil:
@ -206,6 +206,6 @@ proc spawnXsltActor*(turn: var Turn; root: Cap): Actor {.discardable.} =
when isMainModule:
import syndicate/relays
runActor("main") do (turn: var Turn):
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
spawnXsltActor(turn, ds)

View File

@ -1,13 +1,61 @@
# Package
# Emulate Nimble from CycloneDX data at sbom.json.
version = "20240407"
author = "Emery Hemingway"
description = "Utilites for Syndicated Actors and Synit"
license = "unlicense"
srcDir = "src"
bin = @["mintsturdyref", "mount_actor", "msg", "postgre_actor", "preserve_process_environment", "rofi_script_actor", "sqlite_actor", "syndesizer", "syndump", "xslt_actor"]
import std/json
proc lookupComponent(sbom: JsonNode; bomRef: string): JsonNode =
for c in sbom{"components"}.getElems.items:
if c{"bom-ref"}.getStr == bomRef:
return c
result = newJNull()
# Dependencies
let
sbom = "sbom.json".readFile.parseJson
comp = sbom{"metadata", "component"}
bomRef = comp{"bom-ref"}.getStr
requires "http://git.syndicate-lang.org/ehmry/syndicate-nim.git >= 20240405", "https://github.com/ehmry/nim-sys.git#4ef3b624db86e331ba334e705c1aa235d55b05e1", "https://git.sr.ht/~ehmry/nim_taps >= 20240405"
version = comp{"version"}.getStr
author = comp{"authors"}[0]{"name"}.getStr
description = comp{"description"}.getStr
license = comp{"licenses"}[0]{"license", "id"}.getStr
for prop in comp{"properties"}.getElems.items:
let (key, val) = (prop{"name"}.getStr, prop{"value"}.getStr)
case key
of "nim:skipDirs:":
add(skipDirs, val)
of "nim:skipFiles:":
add(skipFiles, val)
of "nim:skipExt":
add(skipExt, val)
of "nim:installDirs":
add(installDirs, val)
of "nim:installFiles":
add(installFiles, val)
of "nim:installExt":
add(installExt, val)
of "nim:binDir":
add(binDir, val)
of "nim:srcDir":
add(srcDir, val)
of "nim:backend":
add(backend, val)
else:
if key.startsWith "nim:bin:":
namedBin[key[9..key.high]] = val
for depend in sbom{"dependencies"}.items:
if depend{"ref"}.getStr == bomRef:
for depRef in depend{"dependsOn"}.items:
let dep = sbom.lookupComponent(depRef.getStr)
var spec = dep{"name"}.getStr
for extRef in dep{"externalReferences"}.elems:
if extRef{"type"}.getStr == "vcs":
spec = extRef{"url"}.getStr
break
let ver = dep{"version"}.getStr
if ver != "":
if ver.allCharsInSet {'0'..'9', '.'}: spec.add " == "
else: spec.add '#'
spec.add ver
requires spec
break