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; } }