Skip to content

.ipc.* — client IPC

Connect to a Rayforce server (./rayforce -p <port>) and exchange messages over TCP. The wire format is the same compact binary serialisation used for ser/de, with automatic delta+RLE compression for payloads larger than 2,000 bytes. All four client builtins live here; the server-side connection hooks (.ipc.on.open / .on.close / .on.sync / .on.async / .on.auth) live on the IPC Connection Hooks page — they are user-settable lambda slots, not registered builtins, so they don't appear in the reference table below.

Restricted under -U

.ipc.open, .ipc.close, and .ipc.send are RAY_FN_RESTRICTED — IPC chaining is blocked on a -U server (a peer cannot dial outward to a third server). .ipc.handle is always available so hooks can read the current connection ID.

Reference

Function Arity Flags Description
.ipc.open unary restricted Open a TCP connection; return an i64 handle.
.ipc.send binary restricted Send a message synchronously; return the server's result.
.ipc.close unary restricted Close a connection handle.
.ipc.handle variadic The current connection's handle inside a server-side hook; -1 otherwise.

.ipc.open

Signature: (.ipc.open "host:port") or (.ipc.open "host:port:user:password").

Returns: an i64 handle. Negative handles never escape — errors are surfaced as Rayfall error objects:

  • type — argument is not a string.
  • domain — malformed address (missing port, port out of (0, 65535], oversized host/user/password).
  • access — server requires auth and you didn't supply credentials, or the password is wrong.
  • io — connection refused / network error.

The handshake exchanges a 2-byte {wire_version, auth_flag} greeting. A wire-version mismatch closes the connection before any payload is exchanged.

;; Unauthenticated
(set h (.ipc.open "127.0.0.1:5000"))

;; With credentials (server started with -u or -U)
(set h (.ipc.open "127.0.0.1:5000:admin:secret123"))

.ipc.send

Signature: (.ipc.send h msg). Sends msg synchronously — blocks until the server replies.

The server's behaviour depends on msg's type:

Payload Server behaviour
STR Parsed as Rayfall, evaluated, result returned.
anything else Passed straight into ray_eval — identity for plain data, execution for an expression list.

Errors: type (h not an i64/i32, or msg not serialisable). Server-side errors are returned as error objects too — .ipc.send does not raise them, the caller decides what to do.

;; String-form query
(.ipc.send h "(select {from: trades where: (> price 100) take: 10})")

;; Expression form — dict stays unevaluated until the server processes it
(.ipc.send h (list select {from: trades by: sym total: (sum qty)}))

;; Plain data round-trips
(.ipc.send h 42)         ;; => 42
(.ipc.send h (til 1000)) ;; => the same vector

Async-fire-and-forget is not exposed at the Rayfall layer — call ray_ipc_send_async from C if you need it. See IPC & Serialization for the wire format and message-type byte.

.ipc.close

Signature: (.ipc.close h). Closes the socket for the handle. Returns the null object.

(.ipc.close h)

.ipc.handle

Signature: (.ipc.handle) — variadic but invoked with no args by convention.

Returns the handle of the connection that triggered the currently-executing server-side hook (.ipc.on.open, .on.close, .on.sync, .on.async, .on.auth). Outside any hook it returns -1.

This is the only way to read the handle inside on.sync / on.async / on.auth, whose lambda signatures don't include h. For on.open and on.close the value always equals the h argument the hook receives.

;; Server-side
(set .ipc.on.open
     (fn [h] (println "opened handle=" (.ipc.handle) " arg=" h)))

;; Outside any hook
(.ipc.handle)
;; => -1

Server-side connection hooks

The five .ipc.on.* slots are user-settable lambdas that intercept the server connection lifecycle. They are not part of the builtin table — install them with plain set:

(set .ipc.on.open  (fn [h] (println "+ " h)))
(set .ipc.on.close (fn [h] (println "- " h)))
(set .ipc.on.sync  (fn [m] (eval (parse m))))
(set .ipc.on.async (fn [m] (eval (parse m))))
(set .ipc.on.auth  (fn [u p] (!= u "ban")))   ;; runs AFTER password check

See IPC Connection Hooks for full semantics: install/clear rules, per-hook error handling, restricted-mode interaction, the reserved-namespace carve-out, and the rejection contract for .ipc.on.auth.

See also