Refactor and document api module
This commit is contained in:
parent
5ddffb510d
commit
92ea7f0aa0
10 changed files with 428 additions and 272 deletions
|
|
@ -4,6 +4,8 @@ version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
jiff = { version = "0.1.15", default-features = false, features = ["std"] }
|
||||||
|
serde = { version = "1.0.215", features = ["derive"] }
|
||||||
serde_json = "1.0.133"
|
serde_json = "1.0.133"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|
|
||||||
21
src/api.rs
21
src/api.rs
|
|
@ -1,17 +1,12 @@
|
||||||
//! Models the [euphoria API][0].
|
//! Models the [euphoria.leet.nu API][0].
|
||||||
//!
|
//!
|
||||||
//! [0]: https://euphoria.leet.nu/heim/api
|
//! [0]: https://euphoria.leet.nu/heim/api
|
||||||
|
|
||||||
mod account_cmds;
|
pub mod account_cmds;
|
||||||
mod events;
|
pub mod events;
|
||||||
pub mod packet;
|
pub mod packets;
|
||||||
mod room_cmds;
|
pub mod room_cmds;
|
||||||
mod session_cmds;
|
pub mod session_cmds;
|
||||||
mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub use account_cmds::*;
|
pub use self::{account_cmds::*, events::*, packets::*, room_cmds::*, session_cmds::*, types::*};
|
||||||
pub use events::*;
|
|
||||||
pub use packet::Data;
|
|
||||||
pub use room_cmds::*;
|
|
||||||
pub use session_cmds::*;
|
|
||||||
pub use types::*;
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
//! Account commands.
|
//! Models [account commands][0] and their replies.
|
||||||
//!
|
//!
|
||||||
//! These commands enable a client to register, associate, and dissociate with
|
//! These commands enable a client to register, associate, and dissociate with
|
||||||
//! an account. An account allows an identity to be shared across browsers and
|
//! an account. An account allows an identity to be shared across browsers and
|
||||||
//! devices, and is a prerequisite for room management
|
//! devices, and is a prerequisite for room management
|
||||||
|
//!
|
||||||
|
//! [0]: https://euphoria.leet.nu/heim/api#account-commands
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -11,6 +13,8 @@ use super::AccountId;
|
||||||
/// Change the primary email address associated with the signed in account.
|
/// Change the primary email address associated with the signed in account.
|
||||||
///
|
///
|
||||||
/// The email address may need to be verified before the change is fully applied.
|
/// The email address may need to be verified before the change is fully applied.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#change-email>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ChangeEmail {
|
pub struct ChangeEmail {
|
||||||
/// The new primary email address for the account.
|
/// The new primary email address for the account.
|
||||||
|
|
@ -32,6 +36,8 @@ pub struct ChangeEmailReply {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the name associated with the signed in account.
|
/// Change the name associated with the signed in account.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#change-name>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ChangeName {
|
pub struct ChangeName {
|
||||||
/// The name to associate with the account.
|
/// The name to associate with the account.
|
||||||
|
|
@ -46,6 +52,8 @@ pub struct ChangeNameReply {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the password of the signed in account.
|
/// Change the password of the signed in account.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#change-password>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ChangePassword {
|
pub struct ChangePassword {
|
||||||
/// The current (and soon-to-be former) password.
|
/// The current (and soon-to-be former) password.
|
||||||
|
|
@ -65,6 +73,8 @@ pub struct ChangePasswordReply {}
|
||||||
/// If the login succeeds, the client should expect to receive a
|
/// If the login succeeds, the client should expect to receive a
|
||||||
/// [`DisconnectEvent`](super::DisconnectEvent) shortly after. The next
|
/// [`DisconnectEvent`](super::DisconnectEvent) shortly after. The next
|
||||||
/// connection the client makes will be a logged in session.
|
/// connection the client makes will be a logged in session.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#login>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Login {
|
pub struct Login {
|
||||||
/// The namespace of a personal identifier.
|
/// The namespace of a personal identifier.
|
||||||
|
|
@ -98,6 +108,8 @@ pub struct LoginReply {
|
||||||
/// If the logout is successful, the client should expect to receive a
|
/// If the logout is successful, the client should expect to receive a
|
||||||
/// [`DisconnectEvent`](super::DisconnectEvent) shortly after. The next
|
/// [`DisconnectEvent`](super::DisconnectEvent) shortly after. The next
|
||||||
/// connection the client makes will be a logged out session.
|
/// connection the client makes will be a logged out session.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#logout>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Logout {}
|
pub struct Logout {}
|
||||||
|
|
||||||
|
|
@ -113,6 +125,8 @@ pub struct LogoutReply {}
|
||||||
/// [`DisconnectEvent`](super::DisconnectEvent) shortly after. The next
|
/// [`DisconnectEvent`](super::DisconnectEvent) shortly after. The next
|
||||||
/// connection the client makes will be a logged in session using the new
|
/// connection the client makes will be a logged in session using the new
|
||||||
/// account.
|
/// account.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#register-account>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RegisterAccount {
|
pub struct RegisterAccount {
|
||||||
/// The namespace of a personal identifier.
|
/// The namespace of a personal identifier.
|
||||||
|
|
@ -145,6 +159,8 @@ pub struct RegisterAccountReply {
|
||||||
///
|
///
|
||||||
/// An error will be returned if the account has no unverified email addresses
|
/// An error will be returned if the account has no unverified email addresses
|
||||||
/// associated with it.
|
/// associated with it.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#resend-verification-email>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ResendVerificationEmail {}
|
pub struct ResendVerificationEmail {}
|
||||||
|
|
||||||
|
|
@ -156,6 +172,8 @@ pub struct ResendVerificationEmailReply {}
|
||||||
///
|
///
|
||||||
/// An email will be sent to the owner of the given personal identifier, with
|
/// An email will be sent to the owner of the given personal identifier, with
|
||||||
/// instructions and a confirmation code for resetting the password.
|
/// instructions and a confirmation code for resetting the password.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#reset-password>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ResetPassword {
|
pub struct ResetPassword {
|
||||||
pub namespace: String,
|
pub namespace: String,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
//! Asynchronous events.
|
//! Models [asynchronous events][0].
|
||||||
|
//!
|
||||||
|
//! [0]: https://euphoria.leet.nu/heim/api#asynchronous-events
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -8,6 +10,8 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Indicates that access to a room is denied.
|
/// Indicates that access to a room is denied.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#bounce-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct BounceEvent {
|
pub struct BounceEvent {
|
||||||
/// The reason why access was denied.
|
/// The reason why access was denied.
|
||||||
|
|
@ -25,16 +29,37 @@ pub struct BounceEvent {
|
||||||
///
|
///
|
||||||
/// If the disconnect reason is `authentication changed`, the client should
|
/// If the disconnect reason is `authentication changed`, the client should
|
||||||
/// immediately reconnect.
|
/// immediately reconnect.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#disconnect-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct DisconnectEvent {
|
pub struct DisconnectEvent {
|
||||||
/// The reason for disconnection.
|
/// The reason for disconnection.
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Indicates that a message in the room has been modified or deleted.
|
||||||
|
///
|
||||||
|
/// If the client offers a user interface and the indicated message is currently
|
||||||
|
/// displayed, it should update its display accordingly.
|
||||||
|
///
|
||||||
|
/// The event packet includes a snapshot of the message post-edit.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#edit-message-event>
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EditMessageEvent {
|
||||||
|
/// The id of the edit.
|
||||||
|
pub edit_id: Snowflake,
|
||||||
|
/// The snapshot of the message post-edit.
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub message: Message,
|
||||||
|
}
|
||||||
|
|
||||||
/// Sent by the server to the client when a session is started.
|
/// Sent by the server to the client when a session is started.
|
||||||
///
|
///
|
||||||
/// It includes information about the client's authentication and associated
|
/// It includes information about the client's authentication and associated
|
||||||
/// identity.
|
/// identity.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#hello-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct HelloEvent {
|
pub struct HelloEvent {
|
||||||
/// The id of the agent or account logged into this session.
|
/// The id of the agent or account logged into this session.
|
||||||
|
|
@ -55,11 +80,15 @@ pub struct HelloEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates a session just joined the room.
|
/// Indicates a session just joined the room.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#join-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct JoinEvent(pub SessionView);
|
pub struct JoinEvent(pub SessionView);
|
||||||
|
|
||||||
/// Sent to all sessions of an agent when that agent is logged in (except for
|
/// Sent to all sessions of an agent when that agent is logged in (except for
|
||||||
/// the session that issued the login command).
|
/// the session that issued the login command).
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#login-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct LoginEvent {
|
pub struct LoginEvent {
|
||||||
pub account_id: AccountId,
|
pub account_id: AccountId,
|
||||||
|
|
@ -67,6 +96,8 @@ pub struct LoginEvent {
|
||||||
|
|
||||||
/// Sent to all sessions of an agent when that agent is logged out (except for
|
/// Sent to all sessions of an agent when that agent is logged out (except for
|
||||||
/// the session that issued the logout command).
|
/// the session that issued the logout command).
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#logout-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct LogoutEvent {}
|
pub struct LogoutEvent {}
|
||||||
|
|
||||||
|
|
@ -75,6 +106,8 @@ pub struct LogoutEvent {}
|
||||||
///
|
///
|
||||||
/// If the network event type is `partition`, then this should be treated as a
|
/// If the network event type is `partition`, then this should be treated as a
|
||||||
/// [`PartEvent`] for all sessions connected to the same server id/era combo.
|
/// [`PartEvent`] for all sessions connected to the same server id/era combo.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#network-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct NetworkEvent {
|
pub struct NetworkEvent {
|
||||||
/// The type of network event; for now, always `partition`.
|
/// The type of network event; for now, always `partition`.
|
||||||
|
|
@ -86,6 +119,8 @@ pub struct NetworkEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Announces a nick change by another session in the room.
|
/// Announces a nick change by another session in the room.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#nick-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct NickEvent {
|
pub struct NickEvent {
|
||||||
/// The id of the session this name applies to.
|
/// The id of the session this name applies to.
|
||||||
|
|
@ -98,22 +133,9 @@ pub struct NickEvent {
|
||||||
pub to: String,
|
pub to: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates that a message in the room has been modified or deleted.
|
|
||||||
///
|
|
||||||
/// If the client offers a user interface and the indicated message is currently
|
|
||||||
/// displayed, it should update its display accordingly.
|
|
||||||
///
|
|
||||||
/// The event packet includes a snapshot of the message post-edit.
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct EditMessageEvent {
|
|
||||||
/// The id of the edit.
|
|
||||||
pub edit_id: Snowflake,
|
|
||||||
/// The snapshot of the message post-edit.
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub message: Message,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates a session just disconnected from the room.
|
/// Indicates a session just disconnected from the room.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#part-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PartEvent(pub SessionView);
|
pub struct PartEvent(pub SessionView);
|
||||||
|
|
||||||
|
|
@ -121,6 +143,8 @@ pub struct PartEvent(pub SessionView);
|
||||||
///
|
///
|
||||||
/// The client should send back a ping-reply with the same value for the time
|
/// The client should send back a ping-reply with the same value for the time
|
||||||
/// field as soon as possible (or risk disconnection).
|
/// field as soon as possible (or risk disconnection).
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#ping-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PingEvent {
|
pub struct PingEvent {
|
||||||
/// A unix timestamp according to the server's clock.
|
/// A unix timestamp according to the server's clock.
|
||||||
|
|
@ -131,6 +155,8 @@ pub struct PingEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Informs the client that another user wants to chat with them privately.
|
/// Informs the client that another user wants to chat with them privately.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#pm-initiate-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PmInitiateEvent {
|
pub struct PmInitiateEvent {
|
||||||
/// The id of the user inviting the client to chat privately.
|
/// The id of the user inviting the client to chat privately.
|
||||||
|
|
@ -144,12 +170,16 @@ pub struct PmInitiateEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates a message received by the room from another session.
|
/// Indicates a message received by the room from another session.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#send-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SendEvent(pub Message);
|
pub struct SendEvent(pub Message);
|
||||||
|
|
||||||
/// Indicates that a session has successfully joined a room.
|
/// Indicates that a session has successfully joined a room.
|
||||||
///
|
///
|
||||||
/// It also offers a snapshot of the room’s state and recent history.
|
/// It also offers a snapshot of the room’s state and recent history.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#snapshot-event>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SnapshotEvent {
|
pub struct SnapshotEvent {
|
||||||
/// The id of the agent or account logged into this session.
|
/// The id of the agent or account logged into this session.
|
||||||
|
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use super::PacketType;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Packet {
|
|
||||||
pub id: Option<String>,
|
|
||||||
pub r#type: PacketType,
|
|
||||||
pub data: Option<Value>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub error: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
||||||
pub throttled: bool,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub throttled_reason: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Command {
|
|
||||||
type Reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! packets {
|
|
||||||
( $( $name:ident, )*) => {
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum Data {
|
|
||||||
$( $name(super::$name), )*
|
|
||||||
Unimplemented,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Data {
|
|
||||||
pub fn from_value(ptype: PacketType, value: Value) -> serde_json::Result<Self> {
|
|
||||||
Ok(match ptype {
|
|
||||||
$( PacketType::$name => Self::$name(serde_json::from_value(value)?), )*
|
|
||||||
_ => Self::Unimplemented,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_value(self) -> serde_json::Result<Value> {
|
|
||||||
Ok(match self{
|
|
||||||
$( Self::$name(p) => serde_json::to_value(p)?, )*
|
|
||||||
Self::Unimplemented => panic!("using unimplemented data"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn packet_type(&self) -> PacketType {
|
|
||||||
match self {
|
|
||||||
$( Self::$name(_) => PacketType::$name, )*
|
|
||||||
Self::Unimplemented => panic!("using unimplemented data"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(
|
|
||||||
impl From<super::$name> for Data {
|
|
||||||
fn from(p: super::$name) -> Self {
|
|
||||||
Self::$name(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Data> for super::$name{
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: Data) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
Data::$name(p) => Ok(p),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! commands {
|
|
||||||
( $( $cmd:ident => $rpl:ident, )* ) => {
|
|
||||||
$(
|
|
||||||
impl Command for super::$cmd {
|
|
||||||
type Reply = super::$rpl;
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
packets! {
|
|
||||||
// Events
|
|
||||||
BounceEvent,
|
|
||||||
DisconnectEvent,
|
|
||||||
HelloEvent,
|
|
||||||
JoinEvent,
|
|
||||||
LoginEvent,
|
|
||||||
LogoutEvent,
|
|
||||||
NetworkEvent,
|
|
||||||
NickEvent,
|
|
||||||
EditMessageEvent,
|
|
||||||
PartEvent,
|
|
||||||
PingEvent,
|
|
||||||
PmInitiateEvent,
|
|
||||||
SendEvent,
|
|
||||||
SnapshotEvent,
|
|
||||||
// Session commands
|
|
||||||
Auth,
|
|
||||||
AuthReply,
|
|
||||||
Ping,
|
|
||||||
PingReply,
|
|
||||||
// Chat room commands
|
|
||||||
GetMessage,
|
|
||||||
GetMessageReply,
|
|
||||||
Log,
|
|
||||||
LogReply,
|
|
||||||
Nick,
|
|
||||||
NickReply,
|
|
||||||
PmInitiate,
|
|
||||||
PmInitiateReply,
|
|
||||||
Send,
|
|
||||||
SendReply,
|
|
||||||
Who,
|
|
||||||
WhoReply,
|
|
||||||
// Account commands
|
|
||||||
ChangeEmail,
|
|
||||||
ChangeEmailReply,
|
|
||||||
ChangeName,
|
|
||||||
ChangeNameReply,
|
|
||||||
ChangePassword,
|
|
||||||
ChangePasswordReply,
|
|
||||||
Login,
|
|
||||||
LoginReply,
|
|
||||||
Logout,
|
|
||||||
LogoutReply,
|
|
||||||
RegisterAccount,
|
|
||||||
RegisterAccountReply,
|
|
||||||
ResendVerificationEmail,
|
|
||||||
ResendVerificationEmailReply,
|
|
||||||
ResetPassword,
|
|
||||||
ResetPasswordReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
commands! {
|
|
||||||
// Session commands
|
|
||||||
Auth => AuthReply,
|
|
||||||
Ping => PingReply,
|
|
||||||
// Chat room commands
|
|
||||||
GetMessage => GetMessageReply,
|
|
||||||
Log => LogReply,
|
|
||||||
Nick => NickReply,
|
|
||||||
PmInitiate => PmInitiateReply,
|
|
||||||
Send => SendReply,
|
|
||||||
Who => WhoReply,
|
|
||||||
// Account commands
|
|
||||||
ChangeEmail => ChangeEmailReply,
|
|
||||||
ChangeName => ChangeNameReply,
|
|
||||||
ChangePassword => ChangePasswordReply,
|
|
||||||
Login => LoginReply,
|
|
||||||
Logout => LogoutReply,
|
|
||||||
RegisterAccount => RegisterAccountReply,
|
|
||||||
ResendVerificationEmail => ResendVerificationEmailReply,
|
|
||||||
ResetPassword => ResetPasswordReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ParsedPacket {
|
|
||||||
pub id: Option<String>,
|
|
||||||
pub r#type: PacketType,
|
|
||||||
pub content: Result<Data, String>,
|
|
||||||
pub throttled: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParsedPacket {
|
|
||||||
pub fn from_packet(packet: Packet) -> serde_json::Result<Self> {
|
|
||||||
let id = packet.id;
|
|
||||||
let r#type = packet.r#type;
|
|
||||||
|
|
||||||
let content = if let Some(error) = packet.error {
|
|
||||||
Err(error)
|
|
||||||
} else {
|
|
||||||
let data = packet.data.unwrap_or_default();
|
|
||||||
Ok(Data::from_value(r#type, data)?)
|
|
||||||
};
|
|
||||||
|
|
||||||
let throttled = if packet.throttled {
|
|
||||||
let reason = packet
|
|
||||||
.throttled_reason
|
|
||||||
.unwrap_or_else(|| "no reason given".to_string());
|
|
||||||
Some(reason)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
id,
|
|
||||||
r#type,
|
|
||||||
content,
|
|
||||||
throttled,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_packet(self) -> serde_json::Result<Packet> {
|
|
||||||
let id = self.id;
|
|
||||||
let r#type = self.r#type;
|
|
||||||
let throttled = self.throttled.is_some();
|
|
||||||
let throttled_reason = self.throttled;
|
|
||||||
|
|
||||||
Ok(match self.content {
|
|
||||||
Ok(data) => Packet {
|
|
||||||
id,
|
|
||||||
r#type,
|
|
||||||
data: Some(data.into_value()?),
|
|
||||||
error: None,
|
|
||||||
throttled,
|
|
||||||
throttled_reason,
|
|
||||||
},
|
|
||||||
Err(error) => Packet {
|
|
||||||
id,
|
|
||||||
r#type,
|
|
||||||
data: None,
|
|
||||||
error: Some(error),
|
|
||||||
throttled,
|
|
||||||
throttled_reason,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
294
src/api/packets.rs
Normal file
294
src/api/packets.rs
Normal file
|
|
@ -0,0 +1,294 @@
|
||||||
|
//! Models the [packets][0] sent between the server and client.
|
||||||
|
//!
|
||||||
|
//! [0]: https://euphoria.leet.nu/heim/api#packets
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use super::PacketType;
|
||||||
|
|
||||||
|
/// A "raw" packet.
|
||||||
|
///
|
||||||
|
/// This packet closely matches the [packet representation defined in the
|
||||||
|
/// API][0]. It can contain arbitrary data in the form of a JSON [`Value`]. It
|
||||||
|
/// can also contain both data and an error at the same time.
|
||||||
|
///
|
||||||
|
/// In order to interpret this packet, you probably want to convert it to a
|
||||||
|
/// [`ParsedPacket`] using [`ParsedPacket::from_packet`].
|
||||||
|
///
|
||||||
|
/// [0]: https://euphoria.leet.nu/heim/api#packets
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Packet {
|
||||||
|
/// Client-generated id for associating replies with commands.
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// The type of the command, reply, or event.
|
||||||
|
pub r#type: PacketType,
|
||||||
|
/// The payload of the command, reply, or event.
|
||||||
|
pub data: Option<Value>,
|
||||||
|
/// This field appears in replies if a command fails.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub error: Option<String>,
|
||||||
|
/// This field appears in replies to warn the client that it may be
|
||||||
|
/// flooding.
|
||||||
|
///
|
||||||
|
/// The client should slow down its command rate.
|
||||||
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||||
|
pub throttled: bool,
|
||||||
|
/// If throttled is true, this field describes why.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub throttled_reason: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Models the relationship between command and reply types.
|
||||||
|
///
|
||||||
|
/// This trait is useful for type-safe command-reply APIs.
|
||||||
|
pub trait Command {
|
||||||
|
/// The type of reply one can expect from the server when sending this
|
||||||
|
/// command.
|
||||||
|
type Reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! packets {
|
||||||
|
( $( $mod:ident::$name:ident, )*) => {
|
||||||
|
/// A big enum containing most types of packet data.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Data {
|
||||||
|
$( $name(super::$mod::$name), )*
|
||||||
|
/// A valid type of packet data that this library does not model as
|
||||||
|
/// a struct.
|
||||||
|
Unimplemented(PacketType, Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
/// Interpret a JSON [`Value`] as packet data of a specific [`PacketType`].
|
||||||
|
///
|
||||||
|
/// This method may fail if the data is invalid.
|
||||||
|
pub fn from_value(ptype: PacketType, value: Value) -> serde_json::Result<Self> {
|
||||||
|
Ok(match ptype {
|
||||||
|
$( PacketType::$name => Self::$name(serde_json::from_value(value)?), )*
|
||||||
|
_ => Self::Unimplemented(ptype, value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the packet data into a JSON [`Value`].
|
||||||
|
///
|
||||||
|
/// This method may fail if the data fails to serialize.
|
||||||
|
pub fn into_value(self) -> serde_json::Result<Value> {
|
||||||
|
Ok(match self {
|
||||||
|
$( Self::$name(p) => serde_json::to_value(p)?, )*
|
||||||
|
Self::Unimplemented(_, value) => value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`PacketType`] of this packet data.
|
||||||
|
pub fn packet_type(&self) -> PacketType {
|
||||||
|
match self {
|
||||||
|
$( Self::$name(_) => PacketType::$name, )*
|
||||||
|
Self::Unimplemented(ptype, _) => *ptype,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
impl From<super::$mod::$name> for Data {
|
||||||
|
fn from(p: super::$mod::$name) -> Self {
|
||||||
|
Self::$name(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Data> for super::$mod::$name{
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: Data) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
Data::$name(p) => Ok(p),
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! commands {
|
||||||
|
( $( $cmd:ident => $rpl:ident, )* ) => {
|
||||||
|
$(
|
||||||
|
impl Command for super::$cmd {
|
||||||
|
type Reply = super::$rpl;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
packets! {
|
||||||
|
// Events
|
||||||
|
events::BounceEvent,
|
||||||
|
events::DisconnectEvent,
|
||||||
|
events::EditMessageEvent,
|
||||||
|
events::HelloEvent,
|
||||||
|
events::JoinEvent,
|
||||||
|
events::LoginEvent,
|
||||||
|
events::LogoutEvent,
|
||||||
|
events::NetworkEvent,
|
||||||
|
events::NickEvent,
|
||||||
|
events::PartEvent,
|
||||||
|
events::PingEvent,
|
||||||
|
events::PmInitiateEvent,
|
||||||
|
events::SendEvent,
|
||||||
|
events::SnapshotEvent,
|
||||||
|
// Session commands
|
||||||
|
session_cmds::Auth,
|
||||||
|
session_cmds::AuthReply,
|
||||||
|
session_cmds::Ping,
|
||||||
|
session_cmds::PingReply,
|
||||||
|
// Chat room commands
|
||||||
|
room_cmds::GetMessage,
|
||||||
|
room_cmds::GetMessageReply,
|
||||||
|
room_cmds::Log,
|
||||||
|
room_cmds::LogReply,
|
||||||
|
room_cmds::Nick,
|
||||||
|
room_cmds::NickReply,
|
||||||
|
room_cmds::PmInitiate,
|
||||||
|
room_cmds::PmInitiateReply,
|
||||||
|
room_cmds::Send,
|
||||||
|
room_cmds::SendReply,
|
||||||
|
room_cmds::Who,
|
||||||
|
room_cmds::WhoReply,
|
||||||
|
// Account commands
|
||||||
|
account_cmds::ChangeEmail,
|
||||||
|
account_cmds::ChangeEmailReply,
|
||||||
|
account_cmds::ChangeName,
|
||||||
|
account_cmds::ChangeNameReply,
|
||||||
|
account_cmds::ChangePassword,
|
||||||
|
account_cmds::ChangePasswordReply,
|
||||||
|
account_cmds::Login,
|
||||||
|
account_cmds::LoginReply,
|
||||||
|
account_cmds::Logout,
|
||||||
|
account_cmds::LogoutReply,
|
||||||
|
account_cmds::RegisterAccount,
|
||||||
|
account_cmds::RegisterAccountReply,
|
||||||
|
account_cmds::ResendVerificationEmail,
|
||||||
|
account_cmds::ResendVerificationEmailReply,
|
||||||
|
account_cmds::ResetPassword,
|
||||||
|
account_cmds::ResetPasswordReply,
|
||||||
|
}
|
||||||
|
|
||||||
|
commands! {
|
||||||
|
// Session commands
|
||||||
|
Auth => AuthReply,
|
||||||
|
Ping => PingReply,
|
||||||
|
// Chat room commands
|
||||||
|
GetMessage => GetMessageReply,
|
||||||
|
Log => LogReply,
|
||||||
|
Nick => NickReply,
|
||||||
|
PmInitiate => PmInitiateReply,
|
||||||
|
Send => SendReply,
|
||||||
|
Who => WhoReply,
|
||||||
|
// Account commands
|
||||||
|
ChangeEmail => ChangeEmailReply,
|
||||||
|
ChangeName => ChangeNameReply,
|
||||||
|
ChangePassword => ChangePasswordReply,
|
||||||
|
Login => LoginReply,
|
||||||
|
Logout => LogoutReply,
|
||||||
|
RegisterAccount => RegisterAccountReply,
|
||||||
|
ResendVerificationEmail => ResendVerificationEmailReply,
|
||||||
|
ResetPassword => ResetPasswordReply,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A fully parsed and interpreted packet.
|
||||||
|
///
|
||||||
|
/// Compared to [`Packet`], this packet's representation more closely matches
|
||||||
|
/// the actual use of packets.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ParsedPacket {
|
||||||
|
/// Client-generated id for associating replies with commands.
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// The type of the command, reply, or event.
|
||||||
|
pub r#type: PacketType,
|
||||||
|
/// The payload of the command, reply, or event, or an error message if the
|
||||||
|
/// command failed.
|
||||||
|
pub content: Result<Data, String>,
|
||||||
|
/// A warning to the client that it may be flooding.
|
||||||
|
///
|
||||||
|
/// The client should slow down its command rate.
|
||||||
|
pub throttled: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParsedPacket {
|
||||||
|
/// Convert a [`Packet`] into a [`ParsedPacket`].
|
||||||
|
///
|
||||||
|
/// This method may fail if the packet data is invalid.
|
||||||
|
pub fn from_packet(packet: Packet) -> serde_json::Result<Self> {
|
||||||
|
let id = packet.id;
|
||||||
|
let r#type = packet.r#type;
|
||||||
|
|
||||||
|
let content = if let Some(error) = packet.error {
|
||||||
|
Err(error)
|
||||||
|
} else {
|
||||||
|
let data = packet.data.unwrap_or_default();
|
||||||
|
Ok(Data::from_value(r#type, data)?)
|
||||||
|
};
|
||||||
|
|
||||||
|
let throttled = if packet.throttled {
|
||||||
|
let reason = packet
|
||||||
|
.throttled_reason
|
||||||
|
.unwrap_or_else(|| "no reason given".to_string());
|
||||||
|
Some(reason)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
id,
|
||||||
|
r#type,
|
||||||
|
content,
|
||||||
|
throttled,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a [`ParsedPacket`] into a [`Packet`].
|
||||||
|
///
|
||||||
|
/// This method may fail if the packet data fails to serialize.
|
||||||
|
pub fn into_packet(self) -> serde_json::Result<Packet> {
|
||||||
|
let id = self.id;
|
||||||
|
let r#type = self.r#type;
|
||||||
|
let throttled = self.throttled.is_some();
|
||||||
|
let throttled_reason = self.throttled;
|
||||||
|
|
||||||
|
Ok(match self.content {
|
||||||
|
Ok(data) => Packet {
|
||||||
|
id,
|
||||||
|
r#type,
|
||||||
|
data: Some(data.into_value()?),
|
||||||
|
error: None,
|
||||||
|
throttled,
|
||||||
|
throttled_reason,
|
||||||
|
},
|
||||||
|
Err(error) => Packet {
|
||||||
|
id,
|
||||||
|
r#type,
|
||||||
|
data: None,
|
||||||
|
error: Some(error),
|
||||||
|
throttled,
|
||||||
|
throttled_reason,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Packet> for ParsedPacket {
|
||||||
|
type Error = serde_json::Error;
|
||||||
|
|
||||||
|
fn try_from(value: Packet) -> Result<Self, Self::Error> {
|
||||||
|
Self::from_packet(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<ParsedPacket> for Packet {
|
||||||
|
type Error = serde_json::Error;
|
||||||
|
|
||||||
|
fn try_from(value: ParsedPacket) -> Result<Self, Self::Error> {
|
||||||
|
value.into_packet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
//! Chat room commands.
|
//! Models [chat room commands][0] and their replies.
|
||||||
//!
|
//!
|
||||||
//! These commands are available to the client once a session successfully joins
|
//! These commands are available to the client once a session successfully joins
|
||||||
//! a room.
|
//! a room.
|
||||||
|
//!
|
||||||
|
//! [0]: https://euphoria.leet.nu/heim/api#chat-room-commands
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{Message, MessageId, PmId, SessionId, SessionView, UserId};
|
use super::{Message, MessageId, PmId, SessionId, SessionView, UserId};
|
||||||
|
|
||||||
/// Retrieve the full content of a single message in the room.
|
/// Retrieve the full content of a single message in the room.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#get-message>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct GetMessage {
|
pub struct GetMessage {
|
||||||
/// The id of the message to retrieve.
|
/// The id of the message to retrieve.
|
||||||
|
|
@ -23,6 +27,8 @@ pub struct GetMessageReply(pub Message);
|
||||||
/// This can be used to supplement the log provided by
|
/// This can be used to supplement the log provided by
|
||||||
/// [`SnapshotEvent`](super::SnapshotEvent) (for example, when scrolling back
|
/// [`SnapshotEvent`](super::SnapshotEvent) (for example, when scrolling back
|
||||||
/// further in history).
|
/// further in history).
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#log>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Log {
|
pub struct Log {
|
||||||
/// Maximum number of messages to return (up to 1000).
|
/// Maximum number of messages to return (up to 1000).
|
||||||
|
|
@ -44,6 +50,8 @@ pub struct LogReply {
|
||||||
///
|
///
|
||||||
/// This name applies to all messages sent during this session, until the nick
|
/// This name applies to all messages sent during this session, until the nick
|
||||||
/// command is called again.
|
/// command is called again.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#nick>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Nick {
|
pub struct Nick {
|
||||||
/// The requested name (maximum length 36 bytes).
|
/// The requested name (maximum length 36 bytes).
|
||||||
|
|
@ -68,6 +76,8 @@ pub struct NickReply {
|
||||||
|
|
||||||
/// Constructs a virtual room for private messaging between the client and the
|
/// Constructs a virtual room for private messaging between the client and the
|
||||||
/// given [`UserId`].
|
/// given [`UserId`].
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#pm-initiate>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PmInitiate {
|
pub struct PmInitiate {
|
||||||
/// The id of the user to invite to chat privately.
|
/// The id of the user to invite to chat privately.
|
||||||
|
|
@ -94,6 +104,8 @@ pub struct PmInitiateReply {
|
||||||
/// The caller of this command will not receive the corresponding
|
/// The caller of this command will not receive the corresponding
|
||||||
/// [`SendEvent`](super::SendEvent), but will receive the same information in
|
/// [`SendEvent`](super::SendEvent), but will receive the same information in
|
||||||
/// the [`SendReply`].
|
/// the [`SendReply`].
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#send>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Send {
|
pub struct Send {
|
||||||
/// The content of the message (client-defined).
|
/// The content of the message (client-defined).
|
||||||
|
|
@ -109,6 +121,8 @@ pub struct Send {
|
||||||
pub struct SendReply(pub Message);
|
pub struct SendReply(pub Message);
|
||||||
|
|
||||||
/// Request a list of sessions currently joined in the room.
|
/// Request a list of sessions currently joined in the room.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#who>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Who {}
|
pub struct Who {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
//! Session commands.
|
//! Models [session commands][0] and their replies.
|
||||||
//!
|
//!
|
||||||
//! Session management commands are involved in the initial handshake and
|
//! Session management commands are involved in the initial handshake and
|
||||||
//! maintenance of a session.
|
//! maintenance of a session.
|
||||||
|
//!
|
||||||
|
//! [0]: https://euphoria.leet.nu/heim/api#session-commands
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -11,6 +13,8 @@ use super::{AuthOption, Time};
|
||||||
///
|
///
|
||||||
/// This should be sent in response to a [`BounceEvent`](super::BounceEvent) at
|
/// This should be sent in response to a [`BounceEvent`](super::BounceEvent) at
|
||||||
/// the beginning of a session.
|
/// the beginning of a session.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#auth>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
/// The method of authentication.
|
/// The method of authentication.
|
||||||
|
|
@ -32,6 +36,8 @@ pub struct AuthReply {
|
||||||
///
|
///
|
||||||
/// The server will send back a [`PingReply`] with the same timestamp as soon as
|
/// The server will send back a [`PingReply`] with the same timestamp as soon as
|
||||||
/// possible.
|
/// possible.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#ping>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Ping {
|
pub struct Ping {
|
||||||
/// An arbitrary value, intended to be a unix timestamp.
|
/// An arbitrary value, intended to be a unix timestamp.
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,16 @@
|
||||||
//! Field types.
|
//! Models the [field types][0].
|
||||||
|
//!
|
||||||
|
//! [0]: https://euphoria.leet.nu/heim/api#field-types
|
||||||
|
|
||||||
// TODO Add newtype wrappers for different kinds of IDs?
|
use std::{error, fmt, num::ParseIntError, str::FromStr};
|
||||||
|
|
||||||
// Serde's derive macros generate this warning and I can't turn it off locally,
|
|
||||||
// so I'm turning it off for the entire module.
|
|
||||||
#![allow(clippy::use_self)]
|
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::{error, fmt};
|
|
||||||
|
|
||||||
use jiff::Timestamp;
|
use jiff::Timestamp;
|
||||||
use serde::{de, ser, Deserialize, Serialize};
|
use serde::{de, ser, Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
/// Describes an account and its preferred name.
|
/// Describes an account and its preferred name.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#accountview>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct AccountView {
|
pub struct AccountView {
|
||||||
/// The id of the account.
|
/// The id of the account.
|
||||||
|
|
@ -24,6 +20,8 @@ pub struct AccountView {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mode of authentication.
|
/// Mode of authentication.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#authoption>
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum AuthOption {
|
pub enum AuthOption {
|
||||||
|
|
@ -36,6 +34,8 @@ pub enum AuthOption {
|
||||||
///
|
///
|
||||||
/// It corresponds to a chat message, or a post, or any broadcasted event in a
|
/// It corresponds to a chat message, or a post, or any broadcasted event in a
|
||||||
/// room that should appear in the log.
|
/// room that should appear in the log.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#message>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
/// The id of the message (unique within a room).
|
/// The id of the message (unique within a room).
|
||||||
|
|
@ -72,6 +72,8 @@ pub struct Message {
|
||||||
/// The type of a packet.
|
/// The type of a packet.
|
||||||
///
|
///
|
||||||
/// Not all of these types have their corresponding data modeled as a struct.
|
/// Not all of these types have their corresponding data modeled as a struct.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#packettype>
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum PacketType {
|
pub enum PacketType {
|
||||||
|
|
@ -250,6 +252,8 @@ impl fmt::Display for PacketType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes an account to its owner.
|
/// Describes an account to its owner.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#personalaccountview>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PersonalAccountView {
|
pub struct PersonalAccountView {
|
||||||
/// The id of the account.
|
/// The id of the account.
|
||||||
|
|
@ -261,6 +265,8 @@ pub struct PersonalAccountView {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a session and its identity.
|
/// Describes a session and its identity.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#sessionview>
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SessionView {
|
pub struct SessionView {
|
||||||
/// The id of an agent or account (or bot).
|
/// The id of an agent or account (or bot).
|
||||||
|
|
@ -290,6 +296,8 @@ pub struct SessionView {
|
||||||
/// A 13-character string, usually used as aunique identifier for some type of object.
|
/// A 13-character string, usually used as aunique identifier for some type of object.
|
||||||
///
|
///
|
||||||
/// It is the base-36 encoding of an unsigned, 64-bit integer.
|
/// It is the base-36 encoding of an unsigned, 64-bit integer.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#snowflake>
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Snowflake(pub u64);
|
pub struct Snowflake(pub u64);
|
||||||
|
|
||||||
|
|
@ -307,7 +315,7 @@ impl Snowflake {
|
||||||
/// representation of message ids to suddenly use the upper parts of the
|
/// representation of message ids to suddenly use the upper parts of the
|
||||||
/// range, and since message ids mostly consist of a timestamp, this
|
/// range, and since message ids mostly consist of a timestamp, this
|
||||||
/// approach should last until at least 2075.
|
/// approach should last until at least 2075.
|
||||||
pub const MAX: Self = Snowflake(i64::MAX as u64);
|
pub const MAX: Self = Self(i64::MAX as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Snowflake {
|
impl fmt::Display for Snowflake {
|
||||||
|
|
@ -324,6 +332,7 @@ impl fmt::Display for Snowflake {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error that occurred while parsing a [`Snowflake`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseSnowflakeError {
|
pub enum ParseSnowflakeError {
|
||||||
InvalidLength(usize),
|
InvalidLength(usize),
|
||||||
|
|
@ -365,7 +374,7 @@ impl FromStr for Snowflake {
|
||||||
return Err(ParseSnowflakeError::InvalidLength(s.len()));
|
return Err(ParseSnowflakeError::InvalidLength(s.len()));
|
||||||
}
|
}
|
||||||
let n = u64::from_str_radix(s, 36)?;
|
let n = u64::from_str_radix(s, 36)?;
|
||||||
Ok(Snowflake(n))
|
Ok(Self(n))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,6 +411,8 @@ impl<'de> Deserialize<'de> for Snowflake {
|
||||||
|
|
||||||
/// Time is specified as a signed 64-bit integer, giving the number of seconds
|
/// Time is specified as a signed 64-bit integer, giving the number of seconds
|
||||||
/// since the Unix Epoch.
|
/// since the Unix Epoch.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#time>
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Time(pub i64);
|
pub struct Time(pub i64);
|
||||||
|
|
||||||
|
|
@ -426,6 +437,8 @@ impl Time {
|
||||||
///
|
///
|
||||||
/// It is possible for this value to have no prefix and colon, and there is no
|
/// It is possible for this value to have no prefix and colon, and there is no
|
||||||
/// fixed format for the unique value.
|
/// fixed format for the unique value.
|
||||||
|
///
|
||||||
|
/// <https://euphoria.leet.nu/heim/api#userid>
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct UserId(pub String);
|
pub struct UserId(pub String);
|
||||||
|
|
||||||
|
|
@ -435,21 +448,27 @@ impl fmt::Display for UserId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// What kind of user a [`UserId`] is.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum SessionType {
|
pub enum UserType {
|
||||||
Agent,
|
Agent,
|
||||||
Account,
|
Account,
|
||||||
Bot,
|
Bot,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserId {
|
impl UserId {
|
||||||
pub fn session_type(&self) -> Option<SessionType> {
|
/// Retrieve the [`UserType`] of this user.
|
||||||
|
///
|
||||||
|
/// This method can return [`None`] because user IDs used to have no
|
||||||
|
/// associated type. Such user IDs can still occur in old room logs, so
|
||||||
|
/// euphoxide supports them.
|
||||||
|
pub fn user_type(&self) -> Option<UserType> {
|
||||||
if self.0.starts_with("agent:") {
|
if self.0.starts_with("agent:") {
|
||||||
Some(SessionType::Agent)
|
Some(UserType::Agent)
|
||||||
} else if self.0.starts_with("account:") {
|
} else if self.0.starts_with("account:") {
|
||||||
Some(SessionType::Account)
|
Some(UserType::Account)
|
||||||
} else if self.0.starts_with("bot:") {
|
} else if self.0.starts_with("bot:") {
|
||||||
Some(SessionType::Bot)
|
Some(UserType::Bot)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod api;
|
||||||
mod emoji;
|
mod emoji;
|
||||||
|
|
||||||
pub use crate::emoji::Emoji;
|
pub use crate::emoji::Emoji;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue