calog/API.md

14 KiB

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.