Skip to main content

obby_client/
command.rs

1//! What a host asks the connection to do.
2//!
3//! One enum rather than a method per action, because this is the half of the API that crosses into
4//! C, WASM, Python and Dart, and a single tagged value binds far more cheaply than a wide surface.
5
6use alloc::string::String;
7
8/// Whether we are still composing a message.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "obby.ts"))]
12#[cfg_attr(feature = "ts", ts(rename = "TypingState"))]
13#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
14pub enum Typing {
15    /// Typing right now.
16    Active,
17    /// Stopped, with text still in the box.
18    Paused,
19    /// Stopped, with the box empty.
20    Done,
21}
22
23impl Typing {
24    pub(crate) fn as_str(self) -> &'static str {
25        match self {
26            Self::Active => "active",
27            Self::Paused => "paused",
28            Self::Done => "done",
29        }
30    }
31}
32
33/// Something to do on this connection.
34#[derive(Debug, Clone, PartialEq, Eq)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "obby.ts"))]
37#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
38#[non_exhaustive]
39pub enum Command {
40    /// Join a channel.
41    Join {
42        /// The channel to join.
43        channel: String,
44        /// Its key, when it has one.
45        key: Option<String>,
46    },
47    /// Leave a channel.
48    Part {
49        /// The channel to leave.
50        channel: String,
51        /// Why, shown to the others in it.
52        reason: Option<String>,
53    },
54    /// Say something to a channel or a person.
55    SendMessage {
56        /// Where to say it.
57        target: String,
58        /// What to say.
59        text: String,
60    },
61    /// Send a notice, which by convention must never be auto-replied to.
62    SendNotice {
63        /// Where to send it.
64        target: String,
65        /// What to send.
66        text: String,
67    },
68    /// Send a `CTCP ACTION`, the third-person form.
69    SendAction {
70        /// Where to send it.
71        target: String,
72        /// What we are doing.
73        text: String,
74    },
75    /// Change our nick.
76    SetNick {
77        /// The nick to take.
78        nick: String,
79    },
80    /// Set or clear a channel topic.
81    SetTopic {
82        /// The channel.
83        channel: String,
84        /// The new topic, or nothing to clear it.
85        topic: Option<String>,
86    },
87    /// Mark ourselves away, or come back.
88    SetAway {
89        /// The away message, or nothing to come back.
90        message: Option<String>,
91    },
92    /// Say we are typing, so others can show it.
93    SetTyping {
94        /// Who we are typing to.
95        target: String,
96        /// How far along we are.
97        state: Typing,
98    },
99    /// React to a message with an emoji.
100    AddReaction {
101        /// The channel or person the message is in.
102        target: String,
103        /// The message reacted to.
104        msgid: String,
105        /// The emoji.
106        emoji: String,
107    },
108    /// Take a reaction back.
109    RemoveReaction {
110        /// The channel or person the message is in.
111        target: String,
112        /// The message.
113        msgid: String,
114        /// The emoji to remove.
115        emoji: String,
116    },
117    /// Ask the server to delete a message.
118    RedactMessage {
119        /// Where the message is.
120        target: String,
121        /// The message to delete.
122        msgid: String,
123        /// Why, when the server wants a reason.
124        reason: Option<String>,
125    },
126    /// Tell the server how far we have read.
127    MarkRead {
128        /// The channel or person.
129        target: String,
130        /// The last message read, in milliseconds since the Unix epoch. The engine writes the
131        /// `server-time` the wire wants.
132        #[cfg_attr(feature = "ts", ts(type = "number"))]
133        at_ms: u64,
134    },
135    /// Ask for older messages than the ones we hold.
136    ///
137    /// With no `before_msgid`, this asks for the most recent, which is what a fresh window wants.
138    FetchHistory {
139        /// The channel or person.
140        target: String,
141        /// Fetch messages older than the message with this id.
142        before_msgid: Option<String>,
143        /// How many to ask for.
144        limit: u16,
145    },
146    /// Set one of our own metadata keys, or clear it.
147    SetMetadata {
148        /// The key, such as `display-name`, `color` or `avatar`.
149        key: String,
150        /// The value, or nothing to clear the key.
151        value: Option<String>,
152    },
153    /// Ask to be told when these metadata keys change on anyone we can see.
154    SubscribeMetadata {
155        /// The keys to watch.
156        keys: alloc::vec::Vec<String>,
157    },
158    /// Ask the server everything it will say about someone.
159    ///
160    /// The reply is nine numerics; the engine collects them and reports the whole record once.
161    Whois {
162        /// Who to ask about.
163        nick: String,
164    },
165    /// Rename a channel, keeping everyone in it and everything said in it.
166    RenameChannel {
167        /// The channel as it is called now.
168        channel: String,
169        /// What to call it.
170        new_name: String,
171        /// Why, shown to the others in it.
172        reason: Option<String>,
173    },
174    /// Make an invitation link to a channel, or to the network when no channel is named.
175    CreateInviteLink {
176        /// The channel it joins, or nothing to invite to the network.
177        channel: Option<String>,
178        /// What it is for.
179        description: Option<String>,
180    },
181    /// Ask for the invitation links we have made.
182    ListInviteLinks,
183    /// Withdraw an invitation link.
184    DeleteInviteLink {
185        /// Which one, from [`Command::ListInviteLinks`].
186        share_id: String,
187    },
188    /// Redeem an invitation code. Only before registering, which is the point of it.
189    RedeemInviteCode {
190        /// The code, which is the share id of the link that carried it.
191        code: String,
192    },
193    /// Mint a bearer token for one of the network's services, such as its file host.
194    GenerateToken {
195        /// Which service the token is for, such as `FILEHOST`.
196        service: String,
197    },
198    /// Watch these nicks, so the server says when they come and go.
199    WatchNicks {
200        /// The nicks to watch.
201        nicks: alloc::vec::Vec<String>,
202    },
203    /// Stop watching these nicks.
204    UnwatchNicks {
205        /// The nicks to stop watching.
206        nicks: alloc::vec::Vec<String>,
207    },
208    /// Send a voice signalling frame to a room.
209    ///
210    /// The frame is the host's to build, because everything in it comes from the media stack the
211    /// core deliberately knows nothing about.
212    #[cfg(feature = "voice")]
213    SendVoiceSignal {
214        /// The channel to signal in.
215        channel: String,
216        /// The frame. The engine encodes it as the JSON that travels in the tag.
217        signal: crate::voice::Signal,
218    },
219    /// Leave the network.
220    Quit {
221        /// Why.
222        reason: Option<String>,
223    },
224    /// Send a line we do not model. The escape hatch, so a host is never stuck waiting for us.
225    SendRawLine {
226        /// The line, without its terminator.
227        line: String,
228    },
229}