diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2024-10-05 20:32:02 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2024-10-05 22:47:12 -0400 |
| commit | 1fb26ad31d385ddc628e1b73d6a8764981ca6885 (patch) | |
| tree | da226cfc7e054ce93bf37da943a395dee226baa6 /src/login | |
| parent | 8edd5625ad5dde0ef1637d5c89e9901b3ee65d73 (diff) | |
Use `/api/boot` to bootstrap the client.
The client now takes an initial snapshot from the response to `/api/boot`, then picks up the event stream at the immediately-successive event to the moment the snapshot was taken.
This commit removes the following unused endpoints:
* `/api/channels` (GET)
* `/api/channels/:channel/messages` (GET)
The information therein is now part of the boot response. We can always add 'em back, but I wanted to clear the deck for designing something more capable, for dealing with client needs.
Diffstat (limited to 'src/login')
| -rw-r--r-- | src/login/routes.rs | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/login/routes.rs b/src/login/routes.rs index 0874cc3..b0e3fee 100644 --- a/src/login/routes.rs +++ b/src/login/routes.rs @@ -5,12 +5,16 @@ use axum::{ routing::{get, post}, Router, }; +use futures::stream::{self, StreamExt as _, TryStreamExt as _}; use crate::{ app::App, + channel::Channel, clock::RequestedAt, error::{Internal, Unauthorized}, + event::Instant, login::{Login, Password}, + message::{self, Message}, token::{app, extract::IdentityToken}, }; @@ -26,9 +30,21 @@ pub fn router() -> Router<App> { async fn boot(State(app): State<App>, login: Login) -> Result<Boot, Internal> { let resume_point = app.logins().boot_point().await?; + let channels = app.channels().all(resume_point.into()).await?; + let channels = stream::iter(channels) + .then(|channel| async { + app.messages() + .in_channel(&channel.id, resume_point.into()) + .await + .map(|messages| BootChannel::new(channel, messages)) + }) + .try_collect() + .await?; + Ok(Boot { login, resume_point: resume_point.to_string(), + channels, }) } @@ -36,6 +52,55 @@ async fn boot(State(app): State<App>, login: Login) -> Result<Boot, Internal> { struct Boot { login: Login, resume_point: String, + channels: Vec<BootChannel>, +} + +#[derive(serde::Serialize)] +struct BootChannel { + #[serde(flatten)] + channel: Channel, + messages: Vec<BootMessage>, +} + +impl BootChannel { + fn new(channel: Channel, messages: impl IntoIterator<Item = Message>) -> Self { + Self { + channel, + messages: messages.into_iter().map(BootMessage::from).collect(), + } + } +} + +#[derive(serde::Serialize)] +struct BootMessage { + #[serde(flatten)] + sent: Instant, + sender: Login, + message: BootMessageBody, +} + +impl From<Message> for BootMessage { + fn from(message: Message) -> Self { + let Message { + sent, + channel: _, + sender, + id, + body, + } = message; + + Self { + sent, + sender, + message: BootMessageBody { id, body }, + } + } +} + +#[derive(serde::Serialize)] +struct BootMessageBody { + id: message::Id, + body: String, } impl IntoResponse for Boot { |
