Overview
OneClaw provides four built-in channel implementations covering common I/O scenarios: interactive CLI, lightweight TCP sockets, Telegram bot integration, and MQTT pub/sub for IoT. Location:crates/oneclaw-channels/src/
CliChannel
Interactive command-line channel for terminal-based I/O. Always included and the simplest channel for testing and direct interaction. Location:crates/oneclaw-channels/src/cli.rs
Struct
Constructor
new()
Creates a CLI channel with default prompt "oneclaw> ".
with_prompt()
Creates a CLI channel with a custom prompt.
Behavior
-
receive(): Displays prompt, reads line from stdin, returns trimmed input asIncomingMessage- Returns
Ok(None)for empty lines - Returns
Err(OneClawError::Channel("EOF"))on EOF (signals loop to stop) - Blocks until user input is available (async-friendly blocking via tokio)
- Returns
-
send(): Writes message content to stdout with newline -
name(): Returns"cli"
Usage
Thread Safety
CLI channel reads/writes are serialized via tokio async I/O. Safe for concurrent use, but only one instance should be active per process (multiple CLI channels would interleave stdin/stdout).TcpChannel
Line-based TCP socket channel for lightweight IoT sensor communication. Location:crates/oneclaw-channels/src/tcp.rs
Struct
Constructor
new()
Creates a TCP channel listening on the given address.
bind_addr- Address to bind (e.g.,"0.0.0.0:8080","127.0.0.1:0"for random port)
Result<TcpChannel>
Example:
Methods
port()
Returns the port this channel is listening on.
Protocol
Line-based text (UTF-8):- Each line = one message
- Newline (
\n) terminates each message - Simple protocol suitable for IoT sensors and embedded devices
Behavior
-
receive(): Non-blocking receive with short timeouts- Checks internal buffer first (for multi-line bursts)
- Tries to accept new TCP connection (1ms timeout)
- Reads available lines from current client (10ms timeout per line)
- Returns first line as
IncomingMessage, buffers remainder - Returns
Ok(None)if no data available
-
send(): Writes message to currently connected client- Appends newline (
\n) automatically - If client disconnected, logs warning and clears client (does not error)
- If no client connected, message is dropped (logged at debug level)
- Appends newline (
-
name(): Returns"tcp" -
sourceformat:"tcp:{port}"(e.g.,"tcp:8080")
Single Client Mode
TcpChannel handles one client at a time. If a new client connects, the previous connection is replaced. This design is suitable for simple IoT scenarios where sensors connect, send data, and disconnect.Usage
Thread Safety
Internal state (client, buffer) is protected by Mutex. Safe for concurrent polling from single async task (as done by ChannelManager).
TelegramChannel
Telegram Bot API channel using long-polling for message reception and sendMessage API for responses. Location:crates/oneclaw-channels/src/telegram.rs
Struct
Constructor
new()
Creates a Telegram channel. No network call — connection is lazy (verified on first poll).
bot_token- Telegram Bot API token (format:"123456:ABC-DEF1234...")allowed_chat_ids- Whitelist of allowed chat IDs (empty = allow all)polling_timeout- Long-polling timeout in seconds (recommended: 30)
Methods
verify_token()
Verifies bot token by calling Telegram getMe API. Returns bot username on success.
Behavior
-
receive(): Long-polling viagetUpdatesAPI- Checks internal buffer first (for multi-message updates)
- Calls Telegram
getUpdateswith offset (acknowledges previous updates) - Filters messages by whitelist (if configured)
- Tracks
last_chat_idfor reply routing - Returns first message, buffers remainder
- Returns
Ok(None)if no messages (long-poll timed out)
-
send(): Sends message viasendMessageAPI- Auto-splits messages >4000 chars at newline boundaries
- Routes to
chat_idparsed fromdestination(format:"telegram:{chat_id}") - Falls back to
last_chat_idif destination is not telegram-specific - If no
chat_idavailable, message is dropped (logged at debug level)
-
name(): Returns"telegram" -
sourceformat:"telegram:{chat_id}"(e.g.,"telegram:12345")
Message Auto-Splitting
Telegram has a 4096-character message limit. TelegramChannel automatically splits long messages:- Splits at newline boundaries when possible
- If a single line exceeds 4000 chars, hard-cuts at 4000
- Each part is sent sequentially as a separate message
Usage
Standalone Alert Function
send_telegram_alert()
Sends a one-shot alert message without a full TelegramChannel instance. Useful for event handlers or pipelines.
Thread Safety
Internal state (last_update_id, buffer, last_chat_id) is protected by Mutex. Safe for concurrent use.
MqttChannel
MQTT pub/sub channel for IoT sensor communication via MQTT broker (usesrumqttc async client).
Location: crates/oneclaw-channels/src/mqtt.rs
Struct
Constructor
new()
Creates and connects MQTT channel, subscribing to given topics.
host- MQTT broker host (e.g.,"mqtt.example.com")port- MQTT broker port (e.g.,1883for plain,8883for TLS)client_id- Unique client identifiersubscribe_topics- Topics to subscribe to (e.g.,["sensors/+/temp", "sensors/+/humidity"])publish_prefix- Prefix for outgoing messages (e.g.,"oneclaw/alerts")username/password- Optional broker authenticationkeep_alive_secs- Keep-alive interval (recommended: 60)
from_config()
Creates MQTT channel from MqttConfig struct.
Methods
clone_client()
Returns a clone of the AsyncClient for independent publishing (e.g., alert dispatch from event handlers).
AsyncClient is cheap to clone — it’s just a channel sender handle. Use this for parallel alert publishing from pipelines or event handlers without blocking the main channel loop.
Example:
Behavior
-
receive(): Polls MQTT event loop for incoming publish packets- Checks internal buffer first (for multi-message batches)
- Polls event loop with 100ms timeout
- Extracts topic and payload from
Publishpackets - Skips empty payloads
- Buffers messages for sequential delivery
- Returns
Ok(None)if no messages (timeout or no publish events)
-
send(): Publishes message to MQTT topic- Routing:
destination == ""or"mqtt"→ usepublish_prefixdestination.starts_with("mqtt:")→ extract topic (e.g.,"mqtt:sensors/response"→"sensors/response")- Otherwise →
"{publish_prefix}/{destination}"
- QoS:
AtLeastOnce(reliable delivery) - Retain:
false(messages not retained by broker)
- Routing:
-
name(): Returns"mqtt" -
sourceformat:"mqtt:{topic}"(e.g.,"mqtt:sensors/garage/temp")
Topic Routing Examples
Incoming:Usage
Thread Safety
Internal state (eventloop, buffer) is protected by Mutex. AsyncClient is Clone and safe to share. The event loop must be polled from a single task (as done by ChannelManager).
Channel Comparison
| Channel | Use Case | Protocol | Blocking | Connection Model |
|---|---|---|---|---|
| CliChannel | Interactive terminal I/O | stdin/stdout | Yes (user input) | Always connected |
| TcpChannel | Lightweight IoT sensors | Line-based TCP | No (1-10ms timeouts) | Single client |
| TelegramChannel | Bot messaging | Telegram Bot API | No (long-polling) | Many users (whitelist) |
| MqttChannel | IoT pub/sub | MQTT 3.1.1 | No (100ms poll) | Persistent broker |
See Also
- Channel Trait - Core trait definition
- ChannelManager - Multi-channel coordination