diff --git a/src/routes/get_guilds.rs b/src/routes/get_guilds.rs index f05d0d4..a89216a 100644 --- a/src/routes/get_guilds.rs +++ b/src/routes/get_guilds.rs @@ -1,35 +1,34 @@ -use std::collections::HashMap; - use poise::serenity_prelude::Http; -use rocket::{http::{CookieJar, Status}, State}; -use rocket::serde::json::Json; +use rocket::{http::CookieJar, State}; +use rocket::response::stream::{Event, EventStream}; use crate::{cookies::user::USER_ID_COOKIE, models::Settings}; // TODO: Incrementally send guilds #[get("/get_guilds")] -pub async fn get_guilds( - cookies: &CookieJar<'_>, - settings: &State, - http: &State, -) -> Result>, Status> { - let user_id: u64 = match cookies.get_private(USER_ID_COOKIE) { - Some(id) => match id.value().parse() { - Ok(id) => id, - Err(_) => return Err(Status::BadRequest), - }, - None => return Err(Status::Unauthorized), - }; - Ok(Json({ - let mut guild_statuses = HashMap::with_capacity(settings.guilds.len()); +pub async fn get_guilds<'a>( + cookies: &'a CookieJar<'_>, + settings: &'a State, + http: &'a State, +) -> EventStream![Event + 'a] { + // EventStream![] is shorthand for EventStream[Event], + // but we need to pass in a lifetime parameter. + EventStream! { + // TODO: Proper error handling + let user_id: u64 = match cookies.get_private(USER_ID_COOKIE) { + Some(id) => match id.value().parse() { + Ok(id) => id, + Err(_) => panic!("BadRequest"), + // Err(_) => return Err(Status::BadRequest), + }, + None => panic!("Unauthorized"), + // None => return Err(Status::Unauthorized), + }; for guild in &settings.guilds { - guild_statuses.insert(guild.id, { - if guild.hidden { - continue; - } - http.get_member(guild.id, user_id).await.is_ok() - }); + if guild.hidden { + continue; + } + yield Event::data(format!("{},{}", guild.id, http.get_member(guild.id, user_id).await.is_ok())); } - guild_statuses - })) + } } diff --git a/templates/modal.html.tera b/templates/modal.html.tera index 8b8ccb9..a73458e 100644 --- a/templates/modal.html.tera +++ b/templates/modal.html.tera @@ -24,11 +24,43 @@ const dialog = document.querySelector("dialog"); // Fetch guilds let guilds = null; +let is_in_participating_server = null; const getGuilds = async () => { if (guilds === null) { - const response = await fetch("/get_guilds"); - const raw_json = await response.text() - guilds = JSON.parse(raw_json); + // Create the guilds dictionary object + guilds = {}; + + // Create an EventSource object to listen to SSE events + const eventSource = new EventSource('/get_guilds'); + + // Event listener for 'message' events + eventSource.addEventListener('message', event => { + // Parse the data received from the event + const [id, is_member] = event.data.split(','); + + // Add the key-value pair to the guilds dictionary + guilds[id] = is_member === 'true'; + + if (guilds[id]) { + setJoined(id); + is_in_participating_server = true; + } + }); + + // Function to block execution until SSE events are done + function waitForSSE() { + return new Promise(resolve => { + // Event listener for 'error' event + // For some reason errors when completing + eventSource.addEventListener('error', () => { + eventSource.close(); + resolve(); + }); + }); + } + + // Call the function to block execution until SSE events are done + await waitForSSE() } return guilds; } @@ -40,18 +72,29 @@ const showServers = async () => { const guilds = await getGuilds(); Object.keys(guilds).forEach(id => { if (guilds[id]) { - const element = document.getElementById(id); - if (element !== null) { - const button = document.createElement("button"); - button.tagName = "button"; - button.className = "joinButton"; - button.disabled = true; - button.innerHTML = "Joined" - element.querySelector("a").replaceWith(button); - } + setJoined(id); } }) }; +// Switch Join button to Joined for server +const setJoined = id => { + element = document.getElementById(id); + if (element === null) { + return; + } + // Check if already set as joined + a = element.querySelector("a"); + if (a === null) { + return; + } + const button = document.createElement("button"); + button.tagName = "button"; + button.className = "joinButton"; + button.disabled = true; + button.innerHTML = "Joined" + element.querySelector("a").replaceWith(button); +} + // Check for welcomed cookie const welcomed = () => document.cookie.split("; ").includes("welcomed=true"); // Load welcome modal, check if it is necessary @@ -61,15 +104,7 @@ const loadServers = async () => { // in case user pressed Join servers button document.querySelector("dialog .welcome").style.display = "none"; } else { - let is_in_participating_server = false; const guilds = await getGuilds(); - const ids = Object.keys(guilds); - for (let i = 0; i < ids.length; i++) { - if (guilds[ids[i]]) { - is_in_participating_server = true; - break; - } - } if (!is_in_participating_server) { showServers(); }