namespace RelayShared.Services;
///
/// JSON-dispatch contract for the WebSocket "control plane" (non-encrypted,
/// non-realtime requests like auth, key registration, channel CRUD, history fetches).
///
/// The server's ChatSocketBehavior.OnMessage looks at the first JSON property of every
/// incoming text frame:
/// - "Action" present → deserialise into WsControlMessage and dispatch on WsAction.
/// - "Type" present → deserialise into SocketEncryptedMessage/SocketRtcSignalMessage
/// and dispatch on SignalType (the "data plane" — chat messages,
/// RTC signals, edit/delete requests).
///
/// Responses come back as either WsEventMessage (for acks/errors) or one of the
/// Socket*Message types (for streaming data).
///
public enum WsAction
{
/// Verify a Core-issued user token. Fields used: Username, Token.
Authenticate,
/// Register/update the client's RSA public key. Fields used: Username, PublicKey.
RegisterKey,
/// Request the server's public RSA key for outbound encryption. No fields.
GetServerKey,
/// Request the full channel list for this user. No fields.
GetChannels,
/// Request decrypted message history for a channel. Fields used: Username, ChannelId.
GetHistory,
/// Join a voice channel (presence tracking). Fields used: Username, ChannelId.
RtcJoin,
/// Leave a voice channel. Fields used: Username, ChannelId.
RtcLeave,
/// Broadcast "user is typing" to channel peers. Fields used: ChannelId.
SendTyping,
/// Request the edit-history chain for a specific message. Fields used: Username, MessageId, ChannelId.
GetEditHistory,
/// Create a new channel (permission-gated). Fields used: ChannelName, ChannelType, ChannelGroup.
CreateChannel,
/// Soft-delete a channel (permission-gated). Fields used: ChannelId.
DeleteChannel
}
/// Server-to-client event types for acks and errors.
public enum WsEvent
{
/// Reply to Authenticate. Detail = username.
Authenticated,
/// Reply to RegisterKey. Detail = username.
KeyRegistered,
/// Generic error. Detail = human-readable reason shown to the user.
Error
}
///
/// Control-plane envelope. All fields are nullable because each action only uses a subset
/// of them. Serialised as JSON; identified by the presence of the "Action" property.
///
public sealed class WsControlMessage
{
/// The action to perform. Server dispatches on this.
public WsAction Action { get; set; }
/// Mixed-case username as the user typed it on sign-in. Server preserves casing for display.
public string? Username { get; set; }
/// Core-issued auth token. Only set on Authenticate.
public string? Token { get; set; }
/// Base64-encoded RSA public key. Only set on RegisterKey.
public string? PublicKey { get; set; }
/// Surreal record id of a channel (e.g. "channels:xyz"). Used by most channel-scoped actions.
public string? ChannelId { get; set; }
/// Surreal record id of a message. Used by GetEditHistory.
public string? MessageId { get; set; }
/// Channel name on create (e.g. "memes"). Server normalises to lowercase-dashes.
public string? ChannelName { get; set; }
/// Integer cast of ChannelType enum (Text=0, Voice=1, …). Used on CreateChannel.
public int ChannelType { get; set; }
/// Group/category label shown in the sidebar (e.g. "General"). Optional on CreateChannel.
public string? ChannelGroup { get; set; }
}
///
/// Server-to-client ack envelope. Identified by the "Event" JSON property
/// (vs WsControlMessage's "Action" or Socket*Message's "Type").
///
public sealed class WsEventMessage
{
/// Which event this is acknowledging.
public WsEvent Event { get; set; }
/// Human-readable context (username on success, error message on Error).
public string? Detail { get; set; }
}