Utilities for the Syndicated Actor Model
Go to file
Emery Hemingway 624cc7513a http_client: content-type fixes 2024-06-10 17:03:55 +03:00
src http_client: content-type fixes 2024-06-10 17:03:55 +03:00
.envrc syndesizer: absorb sqlite_actor 2024-01-09 14:01:38 +02:00
.gitignore Preserves: #! is now #: 2024-02-08 15:50:19 +00:00
README.md sqlite-actor: convert to gatekeeper protocol 2024-06-04 12:52:12 +03:00
Tupfile Tup: generate rules from sbom.json 2024-06-03 14:01:18 +03:00
Tuprules.jq Tup: generate rules from sbom.json 2024-06-03 14:01:18 +03:00
Tuprules.tup Tup: generate rules from sbom.json 2024-06-03 14:01:18 +03:00
assertions.prs Add XSLT processor 2024-02-09 15:24:45 +00:00
base64.prs Add base64 decoder 2024-04-07 18:15:28 +01:00
config.prs http-driver: update from syndicate-nim 2024-06-06 10:46:18 +03:00
default.nix Tup: generate rules from sbom.json 2024-06-03 14:01:18 +03:00
inotify_actor.prs Add inotify_actor 2023-10-10 19:37:30 +01:00
lock.json Update dependencies 2024-05-30 20:51:58 +03:00
mountpoints.prs Refactor for Syndicate API update 2024-01-09 13:30:00 +02:00
mpv.config-example.pr Adjust to Syndicate-nim changes 2023-05-18 12:41:52 +01:00
net_mapper.prs Add lost net_mapper code 2023-07-01 16:06:16 +01:00
rofi.prs Add rofi_script_actor 2023-10-26 17:20:43 +01:00
sbom.json esc-printer-driver: fresh caps for clients 2024-06-10 17:02:06 +03:00
sql.prs SQL: decompose SQL statements and assert errors 2024-04-09 10:14:38 +01:00
syndicate_utils.nimble Tup: generate rules from sbom.json 2024-06-03 14:01:18 +03:00

README.md

Syndicate utils

Syndesizer

A Syndicate multitool that includes a number of different actors that become active via configuration.

Whether you use a single instance for many protocols or many specialized instances is up to you.

Cache

Observes patterns and reässert the values captured for a given lifetime. Takes the argument <cache { dataspace: #!any lifetime: float }>. The lifetime of a cache counts down from moment a value is asserted.

Example configuration:

? <nixspace ?nixspace> [
  ; Require the nix_actor during observations.
  ?nixspace> ? <Observe <rec eval _> _> [
    $config <require-service <daemon nix_actor>> ]
  ?nixspace> ? <Observe <rec realise _> _> [
    $config <require-service <daemon nix_actor>> ]

  ; Cache anything captured by observers in the $nixspace for an hour.
  ; The nix_actor is not required during caching.
  $config <require-service <daemon syndesizer>>
  $config ? <service-object <daemon syndesizer> ?cap> [
    $cap <cache { dataspace: $nixspace lifetime: 3600.0 }> ]
]

File System Usage

Summarize the size of file-system directory. Equivalent to du -s -b. Query the size of a directory in bytes by observing <file-system-usage "/SOME/PATH" ?size>.

# Configuration example

? <exposed-dataspace ?ds> [

  <require-service <daemon syndesizer>>
  ? <service-object <daemon syndesizer> ?cap> [
    $cap <file-system-usage { dataspace: $ds }>
  ]

]

HTTP driver

Experimental HTTP server that services requests using some version 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. Responds to the gatekeeper step <json-socket-translator { socket: <unix "…"> / <tcp "…" … }> $resolver>.

# MPV configuration example
<require-service <daemon mpv-server>>

<daemon mpv-server {
  argv: [
    "/run/current-system/sw/bin/mpv"
    "--really-quiet"
    "--idle=yes"
    "--no-audio-display"
    "--input-ipc-server=/run/user/1000/mpv.sock"
    "--volume=75"
  ]
  protocol: none
}>

let ?resolver = dataspace
$resolver ? <accepted ?mpvSpace> $mpvSpace [
  # announce the dataspace when the translator is connected
  $config <mpv $mpvSpace>
  $config <bind <ref { oid: "mpv" key: #x"" }> $mpvSpace #f>

  # translate <play-file …> to an MPV command
  ?? <play-file ?file> [
    ! <send { "command": ["loadfile" $file "append-play"] }>
  ]

  # clear the playlist on idle so it doesn't grow indefinitely
  ?? <recv {"event": "idle"}> [
    ! <send { "command": ["playlist-clear"] }>
  ]
]

? <service-state <daemon mpv-server> ready> [
  <require-service <daemon syndesizer>>
  ? <service-object <daemon syndesizer> ?cap> [
    $cap <resolve <json-socket-translator {
        socket: <unix "/run/user/1000/mpv.sock">
      }> $resolver>
  ]
]

JSON Stdio Translator

Executes a command, parses its JSON output, converts to record <recv @jsonData any>, and publishes and messages it to a dataspace.

# Configuration example
<require-service <daemon syndesizer>>

let ?ds = dataspace
<bind <ref {oid: "syndicate" key: #x""}> $ds #f>

? <service-object <daemon syndesizer> ?cap> [
  $cap <json-stdio-translator {
    argv: [
      "yt-dlp"
      "--dump-json"
      "https://youtu.be/RR9GkEXDvog"
    ]
    dataspace: $ds
  }>
]

Pulse proxy

A proxy actor that passes assertions and messages to a configured capability but only asserts observations on a a periodic pulse. This can be used to implement polling behavior.

# Example config
let ?ds = dataspace

<require-service <daemon syndesizer>>
? <service-object <daemon syndesizer> ?cap> [
  $cap <pulse {dataspace: $ds}>
]

$ds ? <pulse 3600.0 ?proxy> [
  $proxy ? <assertion-updated-hourly ?value> [
    $log ! <log "-" {assertion-updated-hourly: $value}>
  ]
]

SQLite

Readonly access to SQLite databases. Asserts rows as records in response to SQL query assertions. Dynamic updates are not implemented.

Can be disabled by passing --define:withSqlite=no to the Nim compiler.

# Configuration example
<require-service <daemon syndesizer>>

let ?sqlspace = dataspace

? <service-object <daemon syndesizer> ?cap> [
  $cap <sqlite {
    dataspace: $sqlspace
    database: "/var/db/example.db"
  }>
]

let ?tuplespace = dataspace

$sqlspace <query "SELECT id, name FROM stuff" $tuplespace>

$tuplespace [
  ? [?id ?name] [
    $log ! <log "-" { row: <example-row $id $name> }>
  ]
  ? <sqlite-error ?msg ?ctx> [
    $log ! <log "-" { msg: $msg ctx: $ctx }>
  ]
]

XML translator

Translates between Preserves and XML according to the Conventions for Common Data Types.

Examples:

  • <xml-translation "<foo a=\"1\"> <bar>hello world!</bar></foo>" <foo {"a": 1}<bar "hello world!">>>
  • <xml-translation "" [#t #f]>
  • <xml-translation "<<</>>" #f>
# Configuration example
? <sharedspace ?ds> [
  $ds ? <Observe <rec xml-translation _> _> $config [
    $config <require-service <daemon syndesizer>>
    $config ? <service-object <daemon syndesizer> ?cap> [
      $cap <xml-translator { dataspace: $ds }>
    ]
  ]
]

esc-printer-driver

A basic ESC/P printer driver.

Takes a path to a printer device file as a command line argument. The driver speaks the gatekeeper protocol and responds to the <print {}> step with a capability that prints 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>>

let ?printer-resolver = dataspace
$printer-resolver ? <accepted ?printer> [
  $printer <italic>
  $printer ! "printer resolved\r\n"
]

? <service-object <daemon printer> ?cap> [
  $cap <resolve <printer {}> $printer-resolver>
  $log ! <log "-" { line: "printer started"}>
]

<daemon printer {
  argv: [ "/bin/esc-printer-driver" "/dev/usb/lp0"]
  protocol: application/syndicate
  clearEnv: #t
}>

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.

mount_actor

Actor for mounting filesystems on Linux.

Sample Syndicate server script:

# Assert a file-system we want to mount.
<mount "/dev/sda3" "/boot" "vfat">

# Transform mount assertions into mount status observations.
? <mount ?source ?target ?fs> [
  ? <mount $source $target $fs _> [ ]
]

# Assert mounting succeded.
? <mount _ ?target _ #t> [
  <service-state <mountpoint $target> ready>
]
# Assert mount failed.
? <mount _ ?target _ <failure _>> [
  <service-state <mountpoint $target> failed>
]

# Assert the details into the machine dataspace.
? <machine-dataspace ?machine> [
  $config ? <mount ?source ?target ?fs ?status> [
    $machine <mount $source $target $fs $status>
  ]
]

# Require the mount_actor daemon.
<require-service <daemon mount_actor>>
<daemon mount_actor {
  argv: ["/home/emery/src/bin/mount_actor"]
  protocol: application/syndicate
}>

# Pass the daemon the config dataspace.
? <service-object <daemon mount_actor> ?cap> [
  $cap { dataspace: $config }
]

msg

A utility that parses its command-line arguments as Preserves and send them as messages to $SYNDICATE_ROUTE. When called as assert (by a symlink or a rename) it will make assertions instead.

PostgreSQL

Readonly access to PostgreSQL databases. Asserts rows as records in response to SQL query assertions. Dynamic updates are not implemented.

let ?postgreStep = <postgre {connection: [["host" "db.example.com"] ["dbname" "example"] ["user" "hackme"]]}>

let ?tuplespace = dataspace
$tuplespace ? ?row [
  $log ! <log "-" { line: $row }>
]

let ?resolver = dataspace
$resolver ? <accepted ?sqlspace> [
  $sqlspace ? <sql-error ?msg ?context> [
    $log ! <log "-" { line: $msg context: $context }>
  ]
  $sqlspace <query [SELECT firstname FROM users] $tuplespace>
]

<require-service <daemon postgre-actor>>
$config ? <service-object <daemon postgre-actor> ?cap> [
  $cap <resolve $postgreStep $resolver>
]

<daemon postgre-actor {
  argv: [ "/bin/postgre-actor" ]
  clearEnv: #t
  protocol: application/syndicate
}>

preserve_process_environment

This utility serializes it's process environment to Preserves and prints it to stdout. It can be used to feed the environment variables of a nested child of the Syndicate server back to the server. For example, to retreive the environmental variables that a desktop manager passed on to its children.

SQLite

Readonly access to SQLite databases. Asserts rows as records in response to SQL query assertions. Dynamic updates are not implemented.

# Configuration example
let ?sqliteStep = <sqlite { database: "/var/db/stuff.db" }>

let ?tuplespace = dataspace
$tuplespace ? ?row [
  $log ! <log "-" { line: $row }>
]

let ?resolver = dataspace
$resolver [
  ? <rejected ?detail> [
    $log ! <log "-" { line: $detail }>
  ]
  ? <accepted ?sqlspace> [
    $log ! <log "-" { sqlspace: $sqlspace }>
    $sqlspace ? <sql-error ?msg ?context> [
      $log ! <log "-" { line: $msg context: $context }>
    ]
    $sqlspace <query [ SELECT local_display_name FROM contacts ] $tuplespace>
  ]
]

<require-service <daemon sqlite-actor>>
$config ? <service-object <daemon sqlite-actor> ?cap> [
  $cap <resolve $sqliteStep $resolver>
]

<daemon sqlite-actor {
  argv: [ "/bin/sqlite-actor" ]
  clearEnv: #t
  protocol: application/syndicate
}>

syndump

Utility for printing assertions and messages. Parses the command-line arguments as a pattern, connects a dataspace via $SYNDICATE_ROUTE, and writes observations to standard-output. Published assertions are prefixed by the + character, retractions by -, and messages by !.

Example

# Print patterns in use, filter down with AWK to only the published patterns.
$ FS=':' syndump '<Observe ? _>' | awk -F : '/^+/ { print $2 }'

XSLT processor

Perform XML stylesheet transformations. For a given textual XSLT stylesheet and a textual XML document generate an abstract XML document in Preserves form. Inputs may be XML text or paths to XML files.

# Configuration example
let ?ds = dataspace
$ds [
  ? <xslt-transform "/stylesheet.xls" "/doc.xml" ?output> [
    ? <xml-translation ?text $output> [
      $log ! <log "-" { xslt-output: $text }>
    ]
  ]
]

<require-service <daemon xslt_actor>>
? <service-object <daemon xslt_actor> ?cap> $cap [
  <xml-translator { dataspace: $ds }>
  <xslt { dataspace: $ds }>
]