sqlite-actor: convert to gatekeeper protocol

This commit is contained in:
Emery Hemingway 2024-06-04 12:49:56 +03:00
parent 0b4aa89311
commit d76f1df350
4 changed files with 58 additions and 35 deletions

View File

@ -414,30 +414,43 @@ It can be used to feed the environment variables of a nested child of the Syndic
## SQLite ## SQLite
Readonly access to SQLite databases. Asserts rows as records in response to SQL query assertions. Dynamic updates are not implemented. Readonly access to SQLite databases.
Asserts rows as records in response to SQL query assertions.
Can be disabled by passing `--define:withSqlite=no` to the Nim compiler. Dynamic updates are not implemented.
``` ```
# Configuration example # Configuration example
<require-service <daemon sqlite_actor>> let ?sqliteStep = <sqlite { database: "/var/db/stuff.db" }>
let ?sqlspace = dataspace
? <service-object <daemon sqlite_actor> ?cap> [
$cap <sqlite {
dataspace: $sqlspace
database: "/var/db/example.db"
}>
]
let ?tuplespace = dataspace let ?tuplespace = dataspace
$tuplespace ? ?row [
$sqlspace <query "SELECT id, name FROM stuff" $tuplespace> $log ! <log "-" { line: $row }>
$tuplespace ? [?id ?name] [
$log ! <log "-" { row: <example-row $id $name> }>
] ]
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 ## syndump

View File

@ -69,6 +69,10 @@
"name": "nim:bin:syndump", "name": "nim:bin:syndump",
"value": "syndump" "value": "syndump"
}, },
{
"name": "nim:bin:sqlite-actor",
"value": "sqlite_actor"
},
{ {
"name": "nim:srcDir", "name": "nim:srcDir",
"value": "src" "value": "src"

View File

@ -40,6 +40,12 @@ type
Base64DecoderArguments* {.preservesRecord: "base64-decoder".} = object Base64DecoderArguments* {.preservesRecord: "base64-decoder".} = object
`field0`*: Base64DecoderArgumentsField0 `field0`*: Base64DecoderArgumentsField0
SqliteStepField0* {.preservesDictionary.} = object
`database`*: string
SqliteStep* {.preservesRecord: "sqlite".} = object
`field0`*: SqliteStepField0
XsltArgumentsField0* {.preservesDictionary.} = object XsltArgumentsField0* {.preservesDictionary.} = object
`dataspace`* {.preservesEmbedded.}: EmbeddedRef `dataspace`* {.preservesEmbedded.}: EmbeddedRef
@ -71,13 +77,6 @@ type
FileSystemUsageArguments* {.preservesRecord: "file-system-usage".} = object FileSystemUsageArguments* {.preservesRecord: "file-system-usage".} = object
`field0`*: FileSystemUsageArgumentsField0 `field0`*: FileSystemUsageArgumentsField0
SqliteArgumentsField0* {.preservesDictionary.} = object
`database`*: string
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
SqliteArguments* {.preservesRecord: "sqlite".} = object
`field0`*: SqliteArgumentsField0
PostgreStepField0* {.preservesDictionary.} = object PostgreStepField0* {.preservesDictionary.} = object
`connection`*: seq[PostgreConnectionParameter] `connection`*: seq[PostgreConnectionParameter]
@ -126,12 +125,12 @@ type
proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments | proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments |
SocketAddress | SocketAddress |
Base64DecoderArguments | Base64DecoderArguments |
SqliteStep |
XsltArguments | XsltArguments |
HttpDriverArguments | HttpDriverArguments |
JsonSocketTranslatorStep | JsonSocketTranslatorStep |
WebhooksArguments | WebhooksArguments |
FileSystemUsageArguments | FileSystemUsageArguments |
SqliteArguments |
PostgreStep | PostgreStep |
TcpAddress | TcpAddress |
CacheArguments | CacheArguments |
@ -147,12 +146,12 @@ proc encode*(x: WebsocketArguments | HttpClientArguments |
JsonTranslatorArguments | JsonTranslatorArguments |
SocketAddress | SocketAddress |
Base64DecoderArguments | Base64DecoderArguments |
SqliteStep |
XsltArguments | XsltArguments |
HttpDriverArguments | HttpDriverArguments |
JsonSocketTranslatorStep | JsonSocketTranslatorStep |
WebhooksArguments | WebhooksArguments |
FileSystemUsageArguments | FileSystemUsageArguments |
SqliteArguments |
PostgreStep | PostgreStep |
TcpAddress | TcpAddress |
CacheArguments | CacheArguments |

View File

@ -1,8 +1,10 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense # SPDX-License-Identifier: Unlicense
import preserves, syndicate import
import ./schema/[config, sql] pkg/preserves,
pkg/syndicate, pkg/syndicate/protocols/[gatekeeper, sturdy],
./schema/[config, sql]
# Avoid Sqlite3 from the standard library because it is # Avoid Sqlite3 from the standard library because it is
# only held together by wishful thinking and dlload. # only held together by wishful thinking and dlload.
@ -107,19 +109,24 @@ proc renderSql(tokens: openarray[Value]): string =
else: else:
return "" return ""
proc spawnSqliteActor*(turn: Turn; root: Cap): Actor {.discardable.} = proc spawnSqliteActor*(turn: Turn; relay: Cap): Actor {.discardable.} =
spawn("sqlite-actor", turn) do (turn: Turn): result = spawnActor(turn, "sqlite") do (turn: Turn):
during(turn, root, ?:SqliteArguments) do (path: string, ds: Cap): let pat = Resolve?:{ 0: SqliteStep.grabTypeFlat, 1: grab() }
during(turn, relay, pat) do (path: string, observer: Cap):
linkActor(turn, path) do (turn: Turn): linkActor(turn, path) do (turn: Turn):
let facet = turn.facet let facet = turn.facet
stderr.writeLine("opening SQLite database ", path) stderr.writeLine("opening SQLite database ", path)
var db: Sqlite3 var db: Sqlite3
if open_v2(path, addr db, SQLITE_OPEN_READONLY, nil) != SQLITE_OK: if open_v2(path, addr db, SQLITE_OPEN_READONLY, nil) != SQLITE_OK:
assertError(facet, ds, db, path) discard publish(turn, observer,
Rejected(detail: toPreserves($errmsg(db))))
else: else:
turn.onStop do (turn: Turn): turn.onStop do (turn: Turn):
close(db) close(db)
stderr.writeLine("closed SQLite database ", path) stderr.writeLine("closed SQLite database ", path)
let ds = turn.newDataspace()
discard publish(turn, observer,
ResolvedAccepted(responderSession: ds))
during(turn, ds, ?:Query) do (statement: seq[Value], target: Cap): during(turn, ds, ?:Query) do (statement: seq[Value], target: Cap):
var var
stmt: Stmt stmt: Stmt
@ -145,5 +152,5 @@ proc spawnSqliteActor*(turn: Turn; root: Cap): Actor {.discardable.} =
when isMainModule: when isMainModule:
import syndicate/relays import syndicate/relays
runActor("main") do (turn: Turn): runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; ds: Cap): resolveEnvironment(turn) do (turn: Turn; relay: Cap):
spawnSqliteActor(turn, ds) spawnSqliteActor(turn, relay)