calog script API reference
Every function below is a native that calog registers into each engine, so a script in
any language can call it. This reference covers the natives the calog runner and its
libraries expose. (For the C embedding API -- calogCreate, calogRegister, calogFnInvoke,
etc. -- see the README and src/calog.h.)
Conventions
- Calling syntax per engine. Most engines call a native by its bare name --
cryptoUuid(), kvSet("k", 1). Two differ:
- Wren:
Calog.call("name", [args]), e.g. Calog.call("kvSet", ["k", 1]).
- Scheme (s7): s-expression form,
(kvSet "k" 1).
- Output & exit (provided by the
calog runner): calogPrint(...) writes to stdout;
calogExit([code]) tears everything down and exits. calog is event-driven, so a script
must call calogExit (or be interrupted) to end -- a finished top level does not exit.
- Values. Arguments and results marshal through one canonical type:
nil, bool, int,
real, string, list, and map (keyed record). Strings are binary-safe (may contain
embedded NULs) everywhere the underlying library allows it.
- Signatures. Every entry is written
name(param: type, ...) -> returnType, using the
value types above plus handle (an opaque int64 resource handle), fn (a function value),
and any (a value of any type). [x] marks an optional argument and ...x a variadic one.
A signature with no -> returns nil. A return type given as T | nil may be nil (e.g.
a lookup miss or end of stream).
- Handles (db connections, sockets, ssh sessions, tasks) are opaque int64 values from a
process-wide table, so a handle can be passed to another context and used there -- e.g.
lent to a function in another script via
calogCall, which uses it and returns while the
caller is blocked (a safe synchronous hand-off). What is not safe is using one handle from
two contexts at the same instant, or closing it while another context is mid-operation: at
most one context may touch a given handle at any moment, and exactly one closes it. (Tasks are
the exception -- a task is owner-scoped: only its spawner may taskEval/taskClose it.)
- Callbacks. Natives that take a
fn argument (psSubscribe, timerAfter, timerEvery,
calogExport) accept a first-class function value in every engine. A function value handed
to a script (say, returned by calogCall) is invoked directly -- except in my-basic, which
calls it with calogInvoke(fn, ...args).
- Availability. Every library in this reference is compiled into
bin/calog: crypto,
json, kv, fs, time, timer, export, pubsub, task, net (TCP / UDP / ENet), db (SQLite /
PostgreSQL / MySQL), http, and ssh. ssh needs a reachable server; http needs a reachable
endpoint.
Runner (calog binary)
| Function |
Description |
calogPrint(...values: any) |
Write each argument to stdout, space-separated, with a trailing newline. |
calogExit([code: int]) |
Tear down the runtime and exit the process with code (default 0). Does not return. |
crypto
Binary-safe cryptographic primitives over OpenSSL.
| Function |
Description |
cryptoHashSha256(data: string) -> string |
SHA-256 as a 64-char lowercase hex digest. |
cryptoHashSha1(data: string) -> string |
SHA-1 as a 40-char lowercase hex digest. |
cryptoHmacSha256(key: string, data: string) -> string |
HMAC-SHA-256 as 64-char lowercase hex. |
cryptoRandomBytes(count: int) -> string |
count cryptographically-random bytes. |
cryptoBase64Encode(data: string) -> string |
Base64-encode. |
cryptoBase64Decode(text: string) -> string |
Base64-decode (trailing whitespace tolerated). |
cryptoHexEncode(data: string) -> string |
Lowercase hex encode. |
cryptoHexDecode(hexText: string) -> string |
Hex decode (case-insensitive). |
cryptoUuid() -> string |
A random RFC 4122 version-4 UUID string. |
db
SQL over SQLite, PostgreSQL, and MySQL/MariaDB. Parameters are always bound (never
string-spliced), so queries are injection-safe. Values marshal as: NULL <-> nil, integers/
reals as-is, text and BLOBs as binary-safe strings.
| Function |
Description |
dbOpen(driver: string, conn: string) -> handle |
Open a connection. driver is "sqlite", "postgres", or "mysql". conn is a SQLite path or ":memory:", a libpq conninfo, or a MySQL key=value ... string. |
dbExec(handle: handle, sql: string, ...params: any) -> int |
Run a non-query statement with bound params; returns rows affected. |
dbQuery(handle: handle, sql: string, ...params: any) -> list |
Run a query; returns a list of {column: value} row maps. |
dbClose(handle: handle) |
Close the connection. |
export
Share a function by name across contexts and engines.
| Function |
Description |
calogExport(name: string, fn: fn) |
Publish function fn under a global name. |
calogUnexport(name: string) |
Remove an exported name. |
calogCall(name: string, ...args: any) -> any |
Call an exported function by name -- works in every engine. (An export is also reachable by its bare name -- exportedFn(args) -- on Lua/JS/Squirrel/s7, and on my-basic case-insensitively, since it uppercases identifiers; Wren and Berry always need calogCall.) |
fs
POSIX filesystem access. A failed operation raises a catchable script error carrying
strerror(errno).
| Function |
Description |
fsRead(path: string) -> string |
Read a whole file (binary-safe). |
fsWrite(path: string, data: string) |
Create/truncate and write data. |
fsAppend(path: string, data: string) |
Create if absent, append at the end. |
fsExists(path: string) -> bool |
Whether the path exists. |
fsRemove(path: string) |
Unlink a file. |
fsMkdir(path: string) |
Create one directory level (existing dir is OK). |
fsList(path: string) -> list |
Entry name strings, excluding . and ... |
fsStat(path: string) -> map | nil |
{size, isDir, isFile, mtime}, or nil if the path is absent. |
http
Minimal HTTP/1.1 client over http:// and https://. Each call is its own connection
(Connection: close). 3xx redirects are followed (up to 16, to break loops). https://
verifies the server certificate against the system CA store by default.
| Function |
Description |
httpGet(url: string) -> map |
GET a URL, following redirects. Returns {status, body, headers} (headers keyed by lowercased name). |
httpRequest(opts: map) -> map |
opts is {method (default "GET"), url, headers (map), body, insecure (bool), maxRedirects (int, default 16; 0 = don't follow)}. insecure=true skips TLS verification. Returns {status, body, headers}. |
json
| Function |
Description |
jsonParse(text: string) -> any |
Parse JSON: object -> map, array -> list, number -> int or real, string, true/false, null -> nil. |
jsonStringify(value: any) -> string |
Serialize a value to compact JSON text. |
kv
A process-wide, thread-safe store shared by every context and engine. Holds data only (a
function value is rejected). Keys are binary-safe.
| Function |
Description |
kvSet(key: string, value: any) |
Store a deep copy of value under key (replaces any existing). |
kvGet(key: string) -> any | nil |
A deep copy of the stored value, or nil if absent. |
kvHas(key: string) -> bool |
Whether the key is present. |
kvDelete(key: string) |
Remove the key (no error if absent). |
kvKeys() -> list |
A list of the stored keys (strings). |
net
Three first-class transports -- TCP, UDP, and ENet (reliable/ordered delivery
over UDP) -- all always available. Payloads are binary-safe strings. Blocking calls
(tcpAccept/tcpRecv/udpRecvFrom/enetService) stall only the calling context's thread.
TCP and UDP:
| Function |
Description |
tcpConnect(host: string, port: int) -> handle |
Connect to a TCP server. |
tcpListen(port: int) -> handle |
Listen on a TCP port. |
tcpAccept(handle: handle) -> handle |
Block for a client; returns a connection handle. |
tcpSend(handle: handle, data: string) -> int |
Send all of data; returns bytes sent. |
tcpRecv(handle: handle, maxBytes: int) -> string | nil |
Read up to maxBytes; nil at end of stream. |
tcpClose(handle: handle) |
Close a socket. |
udpOpen(port: int) -> handle |
Open a UDP socket (port 0 = ephemeral). |
udpSendTo(handle: handle, host: string, port: int, data: string) -> int |
Send a datagram; returns bytes sent. |
udpRecvFrom(handle: handle, maxBytes: int) -> map |
Receive one datagram: {data, host, port}. |
udpClose(handle: handle) |
Close a UDP socket. |
ENet (reliable UDP -- ordered, reliable channels over UDP):
| Function |
Description |
enetHost(port: int, maxPeers: int) -> handle |
Create an ENet host. |
enetConnect(hostHandle: handle, host: string, port: int, channels: int) -> handle |
Initiate a connection to a peer; returns a peer handle. |
enetService(hostHandle: handle, timeoutMs: int) -> map |
Poll for one event within timeoutMs. Returns {type, ...} where type is "none", "connect", "receive" (with peer, channel, data), or "disconnect". |
enetSend(peerHandle: handle, channel: int, data: string, reliable: bool) |
Queue a packet on a channel. |
enetDisconnect(peerHandle: handle) |
Begin disconnecting a peer. |
enetClose(hostHandle: handle) |
Destroy an ENet host. |
pubsub
Deliver a message to every subscriber of a topic, across contexts and engines. Delivery is
synchronous; each subscriber runs on its own context's thread and gets a deep copy of the
message. Keep publish graphs acyclic.
| Function |
Description |
psSubscribe(topic: string, fn: fn) -> int |
Register fn to receive messages published on topic; returns a subscription id. |
psUnsubscribe(id: int) |
Drop the subscription with that id. |
psPublish(topic: string, msg: any) -> int |
Deliver a copy of msg to every subscriber; returns how many were invoked. |
ssh
SSH/SFTP over libssh2. Requires a reachable SSH server. Payloads are binary-safe. A connection
handle can be passed to and used by another context (see Handles above), but a libssh2 session
is not thread-safe: never operate on one handle from two contexts at once -- calog does not
serialize it for you.
| Function |
Description |
sshConnect(host: string[, port: int]) -> handle |
Connect (port defaults to 22). |
sshAuthPassword(handle: handle, user: string, password: string) -> bool |
Password authentication. |
sshAuthKey(handle: handle, user: string, privateKeyPath: string[, publicKeyPath: string, passphrase: string]) -> bool |
Public-key authentication. |
sshExec(handle: handle, command: string) -> map |
Run a remote command: {stdout, stderr, exitCode}. |
sshClose(handle: handle) |
Close the session. |
sftpGet(handle: handle, remotePath: string) -> string |
Read a remote file whole (binary-safe). |
sftpPut(handle: handle, remotePath: string, data: string) |
Create/truncate a remote file (mode 0644). |
sftpList(handle: handle, path: string) -> list |
[{name, size, isDir}, ...]. |
sftpStat(handle: handle, path: string) -> map | nil |
{size, isDir}, or nil if the path is missing. |
sftpRemove(handle: handle, path: string) |
Remove a remote file. |
sftpMkdir(handle: handle, path: string) |
Create a remote directory (mode 0755). |
task
Launch and manage other calog script contexts. Tasks are fire-and-forget: a spawned context
runs on its own thread; results come back through host natives or the shared kv/pubsub. A
task is owned by the context that spawned it, and only that owner may taskEval/taskClose.
taskClose is cooperative -- a task busy in a pure loop must poll taskActive() and break
out, or the close blocks until the task next returns to the runtime.
| Function |
Description |
taskSpawn(engine: string, code: string) -> handle |
Run a code string on a named engine ("lua", "js", "squirrel", "mybasic", "berry", "s7", "wren"). |
taskLoad(baseName: string) -> handle |
Launch a script file (engine chosen by extension). |
taskEval(handle: handle, code: string) |
Feed more code into a running task (runs on its thread). |
taskClose(handle: handle) |
Ask a task to stop (cooperative: sets its shutdown flag, then waits for its thread to exit). |
taskActive() -> bool |
Called inside a task: false once its owner has asked it to stop. A long loop polls this -- while taskActive() do ... end -- so taskClose need not block. |
taskActive(handle: handle) -> bool |
Called in the owner: whether the task spawned under handle is still open. |
taskExit() |
Called inside a task: retire this task's own context. Deferred -- the current code finishes normally, then the context stops and the runtime reaps it (no owner action needed). |
taskSelf() -> int |
The calling script's own context id. |
taskCount() -> int |
Number of tasks this library currently holds open. |
time
| Function |
Description |
timeNow() -> real |
Wall-clock epoch seconds, fractional (CLOCK_REALTIME). |
timeMonotonic() -> real |
Seconds from an unspecified origin (CLOCK_MONOTONIC); use for intervals. |
timeSleep(ms: int) |
Block the calling context for ms milliseconds. |
timer
One background thread drives every timer; each callback runs on the context that created the
timer.
| Function |
Description |
timerAfter(ms: int, fn: fn) -> int |
Fire fn once, ms milliseconds from now; returns a timer id. |
timerEvery(ms: int, fn: fn) -> int |
Fire fn every ms milliseconds; returns a timer id. |
timerCancel(id: int) |
Stop a pending or repeating timer. |