Echo Bot Example
A simple bot that echoes back any message it receives.
Overview
This is the most basic example of a Signal bot. It demonstrates:
- Receiving messages
- Sending responses
- Basic error handling
- Graceful shutdown
Code
csharp
public static void Main(string[] args)
{
// Configuration
const string apiUrl = "http://localhost:8080";
const string botNumber = "+1234567890"; // Replace with your Signal number
// Create client
var client = new SignalBotClient(x => x.WithBaseUrl(apiUrl).WithNumber(botNumber));
// Cancellation token for graceful shutdown
using var cts = new CancellationTokenSource();
// Handle Ctrl+C
Console.CancelKeyPress += (sender, e) =>
{
Console.WriteLine("\nStopping bot...");
e.Cancel = true;
cts.Cancel();
};
Console.WriteLine("Echo Bot is starting...");
Console.WriteLine($"Bot number: {botNumber}");
Console.WriteLine("Press Ctrl+C to stop\n");
// Start receiving messages
client.StartReceiving(
updateHandler: HandleMessage,
errorHandler: HandleError,
cancellationToken:
cts.Token
);
Console.WriteLine("Bot stopped");
}
public static async Task HandleMessage(ISignalBotClient client, ReceivedMessageEnvelope message, CancellationToken token)
{
var envelope = message.Envelope!;
// Get the text message
var text = envelope.DataMessage?.Message;
// Ignore empty messages
if (string.IsNullOrWhiteSpace(text))
{
return;
}
// Get sender
var sender = message.Envelope?.SourceNumber ?? string.Empty;
// Log received message
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] From {sender}: {text}");
// Echo back with a prefix
var echoMessage = $"You said: {text}";
try
{
// Send the echo
await client.SendMessageAsync(builder => builder.WithMessage(echoMessage).WithRecipient(sender),
cancellationToken: token);
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Echoed back to {sender}");
}
catch (Exception ex)
{
Console.WriteLine($"Error sending echo: {ex.Message}");
}
}
public static async Task HandleError(ISignalBotClient client, Error err, CancellationToken cancellationToken)
{
Console.WriteLine($"[ERROR] {err.Exception?.GetType().Name}: {err.Exception?.Message}");
// Wait a bit before continuing to avoid tight error loops
await Task.Delay(1000, cancellationToken);
}Configuration
Before running, update these values:
csharp
var apiUrl = "http://localhost:8080"; // Your signal-cli-rest-api URL
var botNumber = "+1234567890"; // Your registered Signal numberRunning the Bot
- Make sure signal-cli-rest-api is running:
bash
docker ps | grep signal-api- Run the bot:
bash
dotnet runSend a message to your bot's number from another Signal account
The bot will echo back your message with "You said: " prefix
Expected Output
Echo Bot is starting...
Bot number: +1234567890
Press Ctrl+C to stop
[14:23:15] From +0987654321: Hello!
[14:23:15] Echoed back to +0987654321
[14:23:20] From +0987654321: How are you?
[14:23:20] Echoed back to +0987654321Enhancements
1. Ignore Bot's Own Messages
csharp
static async Task HandleMessage(
SignalBotClient client,
SignalMessage message,
CancellationToken cancellationToken)
{
var botNumber = "+1234567890";
// Ignore messages from the bot itself
if (message.Source == botNumber)
return;
// ... rest of handler
}2. Add Typing Indicator
csharp
// Show typing before replying
await client.SendTypingIndicatorAsync(
number: botNumber,
recipient: sender,
cancellationToken: cancellationToken
);
// Simulate thinking time
await Task.Delay(500, cancellationToken);
// Send the echo
await client.SendMessageAsync(...);3. Handle Group Messages
csharp
static async Task HandleMessage(
SignalBotClient client,
SignalMessage message,
CancellationToken cancellationToken)
{
var text = message.DataMessage?.Message;
if (string.IsNullOrWhiteSpace(text)) return;
var sender = message.Source;
var groupId = message.DataMessage?.GroupId;
// Handle group messages
if (!string.IsNullOrEmpty(groupId))
{
await client.SendMessageAsync(
number: botNumber,
message: $"@{sender} said: {text}",
groupId: groupId,
cancellationToken: cancellationToken
);
}
else
{
// Handle direct messages
await client.SendMessageAsync(
number: botNumber,
message: $"You said: {text}",
recipients: new[] { sender },
cancellationToken: cancellationToken
);
}
}Troubleshooting
Bot not receiving messages?
- Check signal-cli-rest-api is running:
curl http://localhost:8080/v1/about - Verify your number is registered
- Check console for errors
Bot not responding?
- Check the bot number in
SendMessageAsyncmatches your registered number - Verify network connectivity to signal-cli-rest-api
- Check signal-cli-rest-api logs:
docker logs signal-api
Messages received multiple times?
- Normal behavior - messages stay in queue until acknowledged
- They'll stop appearing after being processed
Next Steps
- Add command handling: Command Bot Example
