Command Bot Example
A bot that responds to slash commands like /help, /time, /echo, and more.
Overview
This example demonstrates:
- Command parsing
- Command routing
- Help system
- State management
- Error messages
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);
}Usage Examples
User: /help
Bot: Shows list of available commands
User: /time
Bot: 🕐 Current time: 14:25:30
User: /echo Hello World
Bot: Hello World
User: /ping
Bot: 🏓 Pong!
User: /unknown
Bot: ❓ Unknown command: /unknown. Send /help to see available commands.
Advanced Features
1. Admin-Only Commands
csharp
private static readonly HashSet<string> _adminNumbers = new()
{
"+9999999999"
};
static async Task HandleMessage(
SignalBotClient client,
SignalMessage message,
CancellationToken cancellationToken)
{
var text = message.DataMessage?.Message;
if (string.IsNullOrWhiteSpace(text) || !text.StartsWith("/")) return;
var sender = message.Source;
var command = text.Split(' ')[0].ToLower();
// Check admin commands
if (command.StartsWith("/admin"))
{
if (!_adminNumbers.Contains(sender))
{
await SendMessage(sender, "🔒 Access denied: Admin only", cancellationToken);
return;
}
await HandleAdminCommand(sender, text, cancellationToken);
return;
}
// ... regular command handling
}
static async Task HandleAdminCommand(string sender, string text, CancellationToken ct)
{
var parts = text.Split(' ', 2);
var command = parts[0].ToLower();
switch (command)
{
case "/adminstats":
await SendAdminStats(sender, ct);
break;
case "/adminbroadcast":
if (parts.Length > 1)
await BroadcastMessage(parts[1], ct);
break;
}
}2. Command Cooldowns
csharp
private static readonly Dictionary<string, Dictionary<string, DateTime>> _commandCooldowns = new();
static bool IsOnCooldown(string sender, string command, int cooldownSeconds)
{
if (!_commandCooldowns.ContainsKey(command))
_commandCooldowns[command] = new Dictionary<string, DateTime>();
if (_commandCooldowns[command].TryGetValue(sender, out var lastUse))
{
var remaining = (lastUse.AddSeconds(cooldownSeconds) - DateTime.Now).TotalSeconds;
if (remaining > 0)
{
return true;
}
}
_commandCooldowns[command][sender] = DateTime.Now;
return false;
}
// Usage
static async Task HandleExpensiveCommand(string sender, CancellationToken ct)
{
if (IsOnCooldown(sender, "/expensive", 60))
{
await SendMessage(sender, "⏳ Please wait before using this command again", ct);
return;
}
// Process command
await SendMessage(sender, "✅ Command executed", ct);
}