postgre-actor: convert to gatekeeper protocol
This commit is contained in:
parent
a40cdbce2c
commit
0b4aa89311
49
README.md
49
README.md
|
@ -374,34 +374,37 @@ When called as `assert` (by a symlink or a rename) it will make assertions inste
|
||||||
|
|
||||||
## PostgreSQL
|
## PostgreSQL
|
||||||
|
|
||||||
Readonly access to PostgreSQL databases. Asserts rows as records in response to SQL query assertions. Dynamic updates are not implemented.
|
Readonly access to PostgreSQL databases.
|
||||||
|
Asserts rows as records in response to SQL query assertions.
|
||||||
Can be disabled by passing `--define:withPostgre=no` to the Nim compiler.
|
Dynamic updates are not implemented.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Configuration example
|
let ?postgreStep = <postgre {connection: [["host" "db.example.com"] ["dbname" "example"] ["user" "hackme"]]}>
|
||||||
<require-service <daemon postgre_actor>>
|
|
||||||
|
|
||||||
let ?sqlspace = dataspace
|
|
||||||
|
|
||||||
? <service-object <daemon postgre_actor> ?cap> [
|
|
||||||
$cap <postgre {
|
|
||||||
dataspace: $sqlspace
|
|
||||||
connection: [
|
|
||||||
["host" "example.com"]
|
|
||||||
["dbname" "foobar"]
|
|
||||||
["user" "hackme"]
|
|
||||||
]
|
|
||||||
}>
|
|
||||||
]
|
|
||||||
|
|
||||||
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 ? <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
|
## preserve_process_environment
|
||||||
|
|
|
@ -36,9 +36,8 @@ JsonSocketTranslatorStep = <json-socket-translator {
|
||||||
socket: SocketAddress
|
socket: SocketAddress
|
||||||
}>.
|
}>.
|
||||||
|
|
||||||
PostgreArguments = <postgre {
|
PostgreStep = <postgre {
|
||||||
connection: [PostgreConnectionParameter ...]
|
connection: [PostgreConnectionParameter ...]
|
||||||
dataspace: #:any
|
|
||||||
}>.
|
}>.
|
||||||
PostgreConnectionParameter = [@key string @val string].
|
PostgreConnectionParameter = [@key string @val string].
|
||||||
|
|
||||||
|
@ -48,9 +47,8 @@ PulseArguments = <pulse {
|
||||||
dataspace: #:any
|
dataspace: #:any
|
||||||
}>.
|
}>.
|
||||||
|
|
||||||
SqliteArguments = <sqlite {
|
SqliteStep = <sqlite {
|
||||||
database: string
|
database: string
|
||||||
dataspace: #:any
|
|
||||||
}>.
|
}>.
|
||||||
|
|
||||||
WebhooksArguments = <webhooks {
|
WebhooksArguments = <webhooks {
|
||||||
|
|
|
@ -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]
|
||||||
|
|
||||||
{.passL: "-lpq".}
|
{.passL: "-lpq".}
|
||||||
|
|
||||||
|
@ -105,54 +107,57 @@ proc renderSql(tokens: openarray[Value]): string =
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
proc spawnPostgreActor*(turn: Turn; root: Cap): Actor {.discardable.} =
|
proc spawnPostgreActor*(turn: Turn; relay: Cap): Actor {.discardable.} =
|
||||||
spawn("postgre", turn) do (turn: Turn):
|
result = spawnActor(turn, "postgre") do (turn: Turn):
|
||||||
during(turn, root, ?:PostgreArguments) do (params: StringPairs, ds: Cap):
|
let pat = Resolve?:{ 0: PostgreStep.grabTypeFlat, 1: grab() }
|
||||||
var
|
during(turn, relay, pat) do (params: StringPairs, observer: Cap):
|
||||||
conn: PGconn
|
linkActor(turn, path) do (turn: Turn):
|
||||||
statusHandle: Handle
|
var
|
||||||
(keys, vals) = splitParams(params)
|
(keys, vals) = splitParams(params)
|
||||||
conn = PQconnectdbParams(keys, vals, 0)
|
conn = PQconnectdbParams(keys, vals, 0)
|
||||||
checkPointer(conn)
|
checkPointer(conn)
|
||||||
let
|
let
|
||||||
status = PQstatus(conn)
|
status = PQstatus(conn)
|
||||||
msg = $PQerrorMessage(conn)
|
msg = $PQerrorMessage(conn)
|
||||||
statusHandle = publish(turn, ds,
|
deallocCStringArray(keys)
|
||||||
initRecord("status", toSymbol($status), msg.toPreserves))
|
deallocCStringArray(vals)
|
||||||
if status == CONNECTION_OK:
|
onStop(turn) do (turn: Turn):
|
||||||
during(turn, ds, ?:Query) do (statement: seq[Value], target: Cap):
|
PQfinish(conn)
|
||||||
var text = renderSql statement
|
if status == CONNECTION_OK:
|
||||||
if text == "":
|
let ds = turn.newDataspace()
|
||||||
discard publish(turn, ds, SqlError(msg: "invalid statement", context: $statement))
|
discard publish(turn, ds, initRecord("status", toSymbol($status), msg.toPreserves))
|
||||||
else:
|
during(turn, ds, ?:Query) do (statement: seq[Value], target: Cap):
|
||||||
var
|
var text = renderSql statement
|
||||||
res = PQexec(conn, text)
|
if text == "":
|
||||||
st = PQresultStatus(res)
|
discard publish(turn, ds, SqlError(msg: "invalid statement", context: $statement))
|
||||||
if st == PGRES_TUPLES_OK or st == PGRES_SINGLE_TUPLE:
|
|
||||||
let tuples = PQntuples(res)
|
|
||||||
let fields = PQnfields(res)
|
|
||||||
if tuples > 0 and fields > 0:
|
|
||||||
for r in 0..<tuples:
|
|
||||||
var tupl = initSequence(fields)
|
|
||||||
for f in 0..<fields:
|
|
||||||
tupl[f] = toPreserves($PQgetvalue(res, r, f))
|
|
||||||
discard publish(turn, target, tupl)
|
|
||||||
else:
|
else:
|
||||||
discard publish(turn, ds, SqlError(
|
var
|
||||||
msg: $PQresStatus(st),
|
res = PQexec(conn, text)
|
||||||
context: $PQresultErrorMessage(res),
|
st = PQresultStatus(res)
|
||||||
))
|
if st == PGRES_TUPLES_OK or st == PGRES_SINGLE_TUPLE:
|
||||||
PQclear(res)
|
let tuples = PQntuples(res)
|
||||||
else:
|
let fields = PQnfields(res)
|
||||||
stderr.writeLine "refusing to do anything when status is ", status
|
if tuples > 0 and fields > 0:
|
||||||
do:
|
for r in 0..<tuples:
|
||||||
deallocCStringArray(keys)
|
var tupl = initSequence(fields)
|
||||||
deallocCStringArray(vals)
|
for f in 0..<fields:
|
||||||
PQfinish(conn)
|
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)
|
||||||
|
discard publish(turn, observer,
|
||||||
|
ResolvedAccepted(responderSession: ds))
|
||||||
|
else:
|
||||||
|
discard publish(turn, observer,
|
||||||
|
Rejected(detail: msg.toPreserves))
|
||||||
|
|
||||||
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):
|
||||||
spawnPostgreActor(turn, ds)
|
spawnPostgreActor(turn, relay)
|
||||||
|
|
|
@ -78,6 +78,12 @@ type
|
||||||
SqliteArguments* {.preservesRecord: "sqlite".} = object
|
SqliteArguments* {.preservesRecord: "sqlite".} = object
|
||||||
`field0`*: SqliteArgumentsField0
|
`field0`*: SqliteArgumentsField0
|
||||||
|
|
||||||
|
PostgreStepField0* {.preservesDictionary.} = object
|
||||||
|
`connection`*: seq[PostgreConnectionParameter]
|
||||||
|
|
||||||
|
PostgreStep* {.preservesRecord: "postgre".} = object
|
||||||
|
`field0`*: PostgreStepField0
|
||||||
|
|
||||||
TcpAddress* {.preservesRecord: "tcp".} = object
|
TcpAddress* {.preservesRecord: "tcp".} = object
|
||||||
`host`*: string
|
`host`*: string
|
||||||
`port`*: BiggestInt
|
`port`*: BiggestInt
|
||||||
|
@ -99,19 +105,16 @@ type
|
||||||
`key`*: string
|
`key`*: string
|
||||||
`val`*: string
|
`val`*: string
|
||||||
|
|
||||||
PostgreArgumentsField0* {.preservesDictionary.} = object
|
|
||||||
`connection`*: seq[PostgreConnectionParameter]
|
|
||||||
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
|
|
||||||
|
|
||||||
PostgreArguments* {.preservesRecord: "postgre".} = object
|
|
||||||
`field0`*: PostgreArgumentsField0
|
|
||||||
|
|
||||||
PulseArgumentsField0* {.preservesDictionary.} = object
|
PulseArgumentsField0* {.preservesDictionary.} = object
|
||||||
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
|
`dataspace`* {.preservesEmbedded.}: EmbeddedRef
|
||||||
|
|
||||||
PulseArguments* {.preservesRecord: "pulse".} = object
|
PulseArguments* {.preservesRecord: "pulse".} = object
|
||||||
`field0`*: PulseArgumentsField0
|
`field0`*: PulseArgumentsField0
|
||||||
|
|
||||||
|
Tcp* {.preservesRecord: "tcp".} = object
|
||||||
|
`host`*: string
|
||||||
|
`port`*: BiggestInt
|
||||||
|
|
||||||
UnixAddress* {.preservesRecord: "unix".} = object
|
UnixAddress* {.preservesRecord: "unix".} = object
|
||||||
`path`*: string
|
`path`*: string
|
||||||
|
|
||||||
|
@ -120,10 +123,6 @@ type
|
||||||
PrinterStep* {.preservesRecord: "printer".} = object
|
PrinterStep* {.preservesRecord: "printer".} = object
|
||||||
`field0`*: PrinterStepField0
|
`field0`*: PrinterStepField0
|
||||||
|
|
||||||
Tcp* {.preservesRecord: "tcp".} = object
|
|
||||||
`host`*: string
|
|
||||||
`port`*: BiggestInt
|
|
||||||
|
|
||||||
proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments |
|
proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments |
|
||||||
SocketAddress |
|
SocketAddress |
|
||||||
Base64DecoderArguments |
|
Base64DecoderArguments |
|
||||||
|
@ -133,15 +132,15 @@ proc `$`*(x: WebsocketArguments | HttpClientArguments | JsonTranslatorArguments
|
||||||
WebhooksArguments |
|
WebhooksArguments |
|
||||||
FileSystemUsageArguments |
|
FileSystemUsageArguments |
|
||||||
SqliteArguments |
|
SqliteArguments |
|
||||||
|
PostgreStep |
|
||||||
TcpAddress |
|
TcpAddress |
|
||||||
CacheArguments |
|
CacheArguments |
|
||||||
XmlTranslatorArguments |
|
XmlTranslatorArguments |
|
||||||
PostgreConnectionParameter |
|
PostgreConnectionParameter |
|
||||||
PostgreArguments |
|
|
||||||
PulseArguments |
|
PulseArguments |
|
||||||
|
Tcp |
|
||||||
UnixAddress |
|
UnixAddress |
|
||||||
PrinterStep |
|
PrinterStep): string =
|
||||||
Tcp): string =
|
|
||||||
`$`(toPreserves(x))
|
`$`(toPreserves(x))
|
||||||
|
|
||||||
proc encode*(x: WebsocketArguments | HttpClientArguments |
|
proc encode*(x: WebsocketArguments | HttpClientArguments |
|
||||||
|
@ -154,13 +153,13 @@ proc encode*(x: WebsocketArguments | HttpClientArguments |
|
||||||
WebhooksArguments |
|
WebhooksArguments |
|
||||||
FileSystemUsageArguments |
|
FileSystemUsageArguments |
|
||||||
SqliteArguments |
|
SqliteArguments |
|
||||||
|
PostgreStep |
|
||||||
TcpAddress |
|
TcpAddress |
|
||||||
CacheArguments |
|
CacheArguments |
|
||||||
XmlTranslatorArguments |
|
XmlTranslatorArguments |
|
||||||
PostgreConnectionParameter |
|
PostgreConnectionParameter |
|
||||||
PostgreArguments |
|
|
||||||
PulseArguments |
|
PulseArguments |
|
||||||
|
Tcp |
|
||||||
UnixAddress |
|
UnixAddress |
|
||||||
PrinterStep |
|
PrinterStep): seq[byte] =
|
||||||
Tcp): seq[byte] =
|
|
||||||
encode(toPreserves(x))
|
encode(toPreserves(x))
|
||||||
|
|
|
@ -16,13 +16,13 @@ import ./syndesizer/[
|
||||||
xml_translator]
|
xml_translator]
|
||||||
|
|
||||||
runActor("syndesizer") do (turn: Turn):
|
runActor("syndesizer") do (turn: Turn):
|
||||||
resolveEnvironment(turn) do (turn: Turn; ds: Cap):
|
resolveEnvironment(turn) do (turn: Turn; relay: Cap):
|
||||||
discard spawnTimerDriver(turn, ds)
|
discard spawnTimerDriver(turn, relay)
|
||||||
discard spawnBase64Decoder(turn, ds)
|
discard spawnBase64Decoder(turn, relay)
|
||||||
discard spawnCacheActor(turn, ds)
|
discard spawnCacheActor(turn, relay)
|
||||||
discard spawnFileSystemUsageActor(turn, ds)
|
discard spawnFileSystemUsageActor(turn, relay)
|
||||||
discard spawnHttpDriver(turn, ds)
|
discard spawnHttpDriver(turn, relay)
|
||||||
discard spawnJsonSocketTranslator(turn, ds)
|
discard spawnJsonSocketTranslator(turn, relay)
|
||||||
discard spawnJsonStdioTranslator(turn, ds)
|
discard spawnJsonStdioTranslator(turn, relay)
|
||||||
discard spawnPulseActor(turn, ds)
|
discard spawnPulseActor(turn, relay)
|
||||||
discard spawnXmlTranslator(turn, ds)
|
discard spawnXmlTranslator(turn, relay)
|
||||||
|
|
Loading…
Reference in New Issue