# SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense import preserves, syndicate, syndicate/relays import ../schema/[config, sql] {.passL: "-lpq".} {.pragma: libpq, header: "libpq-fe.h", importc.} type PGconn* {.libpq.} = ptr object ConnStatusType* {.libpq.} = enum CONNECTION_OK, CONNECTION_BAD, ## Non-blocking mode only below here ## ## The existence of these should never be relied upon - they should only ## be used for user feedback or similar purposes. ## CONNECTION_STARTED, ## Waiting for connection to be made. CONNECTION_MADE, ## Connection OK; waiting to send. CONNECTION_AWAITING_RESPONSE, ## Waiting for a response from the ## postmaster. CONNECTION_AUTH_OK, ## Received authentication; waiting for ## backend startup. CONNECTION_SETENV, ## This state is no longer used. CONNECTION_SSL_STARTUP, ## Negotiating SSL. CONNECTION_NEEDED, ## Internal state: connect() needed CONNECTION_CHECK_WRITABLE, ## Checking if session is read-write. CONNECTION_CONSUME, ## Consuming any extra messages. CONNECTION_GSS_STARTUP, ## Negotiating GSSAPI. CONNECTION_CHECK_TARGET, ## Checking target server properties. CONNECTION_CHECK_STANDBY ## Checking if server is in standby mode. proc PQconnectdbParams( keywords: cstringArray; values: cstringArray; expand_dbname: cint): PGconn {.libpq.} proc PQerrorMessage(conn: PGconn): cstring {.libpq.} proc PQfinish(conn: PGconn) {.libpq.} proc PQstatus(conn: PGconn): ConnStatusType {.libpq.} # proc PQsocket(conn: PGconn): cint # proc PQconnectStartParams( # keywords: cstringArray; values: cstringArray; expand_dbname: cint): PGconn # TODO: async type StringPairs = seq[tuple[key: string, val: string]] proc splitParams(params: StringPairs): (cstringArray, cstringArray) = var strings = newSeq[string](params.len) for i, _ in params: strings[i] = params[i][0] result[0] = allocCStringArray(strings) 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): during(turn, root, ?:PostgreArguments) do (params: StringPairs, ds: Cap): var conn: PGconn statusHandle: Handle block: var (keys, vals) = splitParams(params) conn = PQconnectdbParams(keys, vals, 0) deallocCStringArray(keys) deallocCStringArray(vals) if conn.isNil: raise newException(OutOfMemDefect, "failed to alloc PQ connection") let status = PQstatus(conn) msg = $PQerrorMessage(conn) statusHandle = publish(turn, ds, initRecord("status", toSymbol($status), msg.toPreserves)) if status == CONNECTION_OK: discard do: PQfinish(conn) when isMainModule: runActor("main") do (turn: var Turn; root: Cap): connectStdio(turn, root) spawnPostgreActor(turn, root)