Add channel system with CLI, Telegram, and Web channel implementations

Define channel abstractions (IChannel, IChannelManager) with event-driven
message and connection handling. Implement ChannelManager for multi-channel
orchestration, CliChannel for terminal I/O, TelegramChannel with adapter
pattern for bot API integration, and WebChannel stub. Includes DI
registration and channel type enumeration.
This commit is contained in:
2026-04-04 04:12:11 +02:00
parent dd35e1dea6
commit 9a05bae4a9
13 changed files with 642 additions and 0 deletions
@@ -0,0 +1,27 @@
namespace Luna.Channels.Abstractions;
/// <summary>
/// Event arguments for channel connection state changes
/// </summary>
public class ChannelConnectionEventArgs : EventArgs
{
/// <summary>
/// The channel whose connection state changed
/// </summary>
public required IChannel Channel { get; init; }
/// <summary>
/// The previous connection state
/// </summary>
public bool WasConnected { get; init; }
/// <summary>
/// The new connection state
/// </summary>
public bool IsConnected { get; init; }
/// <summary>
/// Optional error message if connection failed
/// </summary>
public string? ErrorMessage { get; init; }
}
@@ -0,0 +1,25 @@
using Luna.Shared;
namespace Luna.Channels.Abstractions;
/// <summary>
/// Event arguments for when a message is received from a channel
/// </summary>
public class ChannelMessageReceivedEventArgs : EventArgs
{
/// <summary>
/// The received message
/// </summary>
public required ChannelMessage Message { get; init; }
/// <summary>
/// The channel that received the message
/// </summary>
public required IChannel Channel { get; init; }
/// <summary>
/// Set to true to indicate the message has been handled and should not be processed further
/// </summary>
public bool IsHandled { get; set; }
}
@@ -0,0 +1,8 @@
namespace Luna.Channels.Abstractions;
public static class ChannelType
{
public const string Cli = "cli";
public const string Web = "web";
public const string Telegram = "telegram";
}
+60
View File
@@ -0,0 +1,60 @@
using Luna.Shared;
namespace Luna.Channels.Abstractions;
public delegate Task ChannelMessageReceivedEventHandler(object? sender, ChannelMessageReceivedEventArgs args);
public delegate Task ChannelConnectionChangedEventHandler(object? sender, ChannelConnectionEventArgs args);
/// <summary>
/// Represents a communication channel for the Luna AI Assistant.
/// Channels handle sending and receiving messages via different platforms
/// (e.g., CLI, Telegram, Discord, Email).
/// </summary>
public interface IChannel : IDisposable
{
/// <summary>
/// Unique identifier for this channel instance
/// </summary>
string ChannelId { get; }
/// <summary>
/// Type of channel (e.g., "cli", "telegram", "discord")
/// </summary>
string ChannelType { get; }
/// <summary>
/// Display name for the channel
/// </summary>
string DisplayName { get; }
/// <summary>
/// Indicates whether the channel is currently connected and ready
/// </summary>
bool IsConnected { get; }
/// <summary>
/// Event raised when a message is received from the channel
/// </summary>
event ChannelMessageReceivedEventHandler? MessageReceived;
/// <summary>
/// Event raised when the channel connection state changes
/// </summary>
event ChannelConnectionChangedEventHandler? ConnectionStateChanged;
/// <summary>
/// Send a message to the channel
/// </summary>
/// <param name="message">The message to send</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Task representing the send operation</returns>
Task SendMessageAsync(ChannelMessage message, CancellationToken cancellationToken = default);
/// <summary>
/// Send a streaming response to the channel
/// </summary>
/// <param name="messageStream">Async enumerable of response updates</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Task representing the send operation</returns>
Task SendStreamingMessageAsync(IAsyncEnumerable<ChatStreamUpdate> messageStream, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,37 @@
namespace Luna.Channels.Abstractions;
/// <summary>
/// Manages the lifecycle and routing of all registered communication channels.
/// </summary>
public interface IChannelManager
{
/// <summary>
/// Registers a channel with this manager.
/// </summary>
/// <param name="channel"></param>
/// <exception cref="InvalidOperationException">Thrown if a channel with the same ID is already registered.</exception>
void RegisterChannel(IChannel channel);
/// <summary>
/// Unregisters a channel by its ID. No-op if the channel is not found.
/// </summary>
/// <param name="channelId">The ID of the channel to remove.</param>
void UnregisterChannel(string channelId);
/// <summary>
/// Retrieves a registered channel by its ID.
/// </summary>
/// <param name="channelId">The ID of the channel to retrieve.</param>
/// <returns>The channel, or null if not found.</returns>
IChannel? GetChannel(string channelId);
/// <summary>
/// Returns all currently registered channels.
/// </summary>
IReadOnlyList<IChannel> GetAllChannels();
/// <summary>
/// Raised after a message has been received and routed.
/// </summary>
event EventHandler<ChannelMessageReceivedEventArgs>? MessageRouted;
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Luna.Shared\Luna.Shared.csproj" />
</ItemGroup>
</Project>