Giocci

Giocci is an Elixir library for interacting with the GiocciPlatform. It allows you to save Elixir modules to remote engines and execute their functions across the network.

Installation

Add giocci to your list of dependencies in mix.exs:

def deps do
  [
    {:giocci, "~> 0.6.2"}
  ]
end

Configuration

config/config.exs

Configure Giocci in your config/config.exs:

config :giocci,
  zenoh_config_file_path: "path/to/zenoh.json5",  # Path to Zenoh configuration
  client_name: "my_client",                       # Unique client identifier
  key_prefix: ""                                  # Optional key prefix for Zenoh keys

zenoh.json5

See Zenoh DEFAULT_CONFIG.json5 for detailed options.

Environment Variables

Usage

1. Register Client

Register your client with a relay:

:ok = Giocci.register_client("giocci_relay")

2. Save Module

Here, the following module is assumed to be in your Elixir project.

defmodule MyModule do
  def add(a, b), do: a + b
  def multiply(a, b), do: a * b
end

Save an Elixir module to the relay (which distributes it to engines):

:ok = Giocci.save_module("giocci_relay", MyModule)

If the relay loses the client registration (for example after a restart), save_module/3 returns {:error, "client_not_registered"} and logs a warning. Call Giocci.register_client("giocci_relay") again before retrying; the client does not re-register automatically.

3. Execute Function (Synchronous)

Execute a function on a remote engine:

# Execute MyModule.add(1, 2)
result = Giocci.exec_func("giocci_relay", {MyModule, :add, [1, 2]})
# => 3

4. Execute Function (Asynchronous)

Execute a function asynchronously and receive the result as a message:

defmodule MyServer do
  use GenServer

  def start_link(_) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init(_) do
    # Execute async function
    :ok = Giocci.exec_func_async("giocci_relay", {MyModule, :multiply, [3, 4]}, self())
    {:ok, %{}}
  end

  def handle_info({:giocci, result}, state) do
    IO.puts("Received result: #{result}")
    # => "Received result: 12"
    {:noreply, state}
  end
end

Options

All functions accept an optional opts keyword list:

Example:

Giocci.exec_func("giocci_relay", {MyModule, :add, [1, 2]}, timeout: 10_000)

Additional Features

Saving dynamically defined modules

For a module defined interactively in IEx or Livebook, or compiled with Code.compile_string/2 without writing a BEAM file, opt in to retaining its compiled BEAM:

defmodule MyDynamicModule do
  use Giocci.DynamicModule

  def add(a, b), do: a + b
end

:ok = Giocci.save_module("giocci_relay", MyDynamicModule)

Include use Giocci.DynamicModule each time the module is redefined. If it is omitted on redefinition, save_module returns {:error, "dynamic_module_stale"} rather than sending the previous BEAM. Without the opt-in or a BEAM file, it returns {:error, "get_object_code_failed"}. One BEAM per opted-in module is retained until the VM exits; redefining that module replaces the retained BEAM. Regular Mix modules need no opt-in.

Inspecting the platform

Use Giocci.Inspect to check this client's Zenoh connection, relay and engine registrations, saved modules, runtime information, and ping responses.

Giocci.Inspect.connection_info()
Giocci.Inspect.list_relays()
Giocci.Inspect.list_modules("giocci_relay")
Giocci.Inspect.ping_engine("giocci_engine")

list_relays/1 can return partial results with :warn. See the Giocci.Inspect API documentation for return values and query options.

Running with Docker (for Testing)

The Docker environment is provided for troubleshooting network connectivity issues between Giocci, GiocciRelay, and GiocciEngine.

Prerequisites

Setup and Testing

  1. Navigate to the giocci directory:

    cd apps/giocci
  2. Edit config/zenoh.json5 to configure Zenoh connection:

    • This file is copied from the official Zenoh repository and modifiled for Giocci (check MODIFIED_FOR_GIOCCI label in the file).
    • Set connect.endpoints to your Zenohd server address (e.g., ["tcp/192.168.1.100:7447"])
    • Alternatively, set the ZENOHD_CONNECT_ENDPOINTS environment variable (e.g., ZENOHD_CONNECT_ENDPOINTS=tcp/192.168.1.100:7447) to avoid storing the IP address in the config file
  3. Edit config/giocci.exs to configure the client:

    • Set client_name to identify this client instance
    • Ensure relay_name in the config matches your running GiocciRelay instance
  4. Start the client with IEx shell:

    docker compose run --rm giocci
  5. In the IEx shell, run the test:

    iex(giocci@hostname)> Giocci.Sample.Test.exec("giocci_relay")

    Expected output:

    2026-01-14 05:33:10.528 [info] register_client/1 success!
    2026-01-14 05:33:10.537 [info] save_module/2 success!
    2026-01-14 05:33:10.555 [info] exec_func/2 success!
    2026-01-14 05:33:10.556 [info] exec_func_async/3 success!
    :ok

This test verifies:

Troubleshooting

If the test fails or times out, check the logs of your running services:

# Check GiocciRelay logs
docker compose logs -f giocci_relay

# Check GiocciEngine logs
docker compose logs -f giocci_engine

# Check Zenohd logs
docker compose logs -f zenohd

Common issues:

API Reference

See the HexDocs for detailed API documentation.

Architecture

For information about the overall GiocciPlatform architecture and communication flows, see the main README.