/*
* This file is part of sdbclient
* Copyright (C) 2022 Jonni Liljamo <jonni@liljamo.com>
*
* Licensed under GPL-3.0-only.
* See LICENSE for licensing information.
*/
use bevy::{
prelude::*,
tasks::{AsyncComputeTaskPool, Task},
};
use bevy_console::PrintConsoleLine;
use futures_lite::future;
use crate::{
api::{
self,
user::{ResponseToken, ResponseUserInfoP},
},
cfg::{CfgDev, CfgUser},
plugins::config::{SaveEvent, SaveEventValue},
};
use super::MenuState;
pub mod ui;
pub struct AccountLoginPlugin;
impl Plugin for AccountLoginPlugin {
fn build(&self, app: &mut App) {
app.add_state(LoginState::None)
// UI system
.insert_resource(ui::InputsUserLogin::new())
.add_system_set(
SystemSet::on_update(LoginState::Input).with_system(ui::account_login_ui),
)
// Login system, as in calling the API
.add_system_set(
SystemSet::on_enter(LoginState::LoggingIn).with_system(start_login_call),
)
.add_system_set(
SystemSet::on_update(LoginState::LoggingIn).with_system(handle_login_call),
);
}
}
/// Login State
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub enum LoginState {
None,
Input,
LoggingIn,
}
struct LoginCallResponse {
token: ResponseToken,
user_infop: Option<ResponseUserInfoP>,
}
#[derive(Component)]
struct LoginCall(Task<LoginCallResponse>);
fn start_login_call(
mut commands: Commands,
cfg_dev: Res<CfgDev>,
inputs: Res<ui::InputsUserLogin>,
) {
let api_address = cfg_dev.api_server.clone();
let i = inputs.clone();
let thread_pool = AsyncComputeTaskPool::get();
let task = thread_pool.spawn(async move {
let token_response = api::user::token(api_address.clone(), i.email, i.password);
let mut user_infop_response = None;
match &token_response {
ResponseToken::Valid(res) => {
user_infop_response = Some(api::user::userinfop(
api_address,
res.token.clone(),
res.id.clone(),
));
}
#[allow(unused_variables)]
ResponseToken::Error { error } => {}
}
LoginCallResponse {
token: token_response,
user_infop: user_infop_response,
}
});
commands.spawn(LoginCall(task));
}
fn handle_login_call(
mut commands: Commands,
mut login_call_tasks: Query<(Entity, &mut LoginCall)>,
mut inputs: ResMut<ui::InputsUserLogin>,
mut login_state: ResMut<State<LoginState>>,
mut menu_state: ResMut<State<MenuState>>,
mut cfg_user: ResMut<CfgUser>,
mut save_event_writer: EventWriter<SaveEvent>,
mut console: EventWriter<PrintConsoleLine>,
) {
let (entity, mut task) = login_call_tasks.single_mut();
if let Some(login_call_response) = future::block_on(future::poll_once(&mut task.0)) {
match login_call_response.token {
ResponseToken::Valid(res) => {
console.send(PrintConsoleLine::new(
format!("Logged in with: {}", inputs.email).into(),
));
match login_call_response.user_infop.unwrap() {
ResponseUserInfoP::Valid(infop) => {
*cfg_user = CfgUser {
logged_in: true,
user_token: res.token,
id: res.id,
username: infop.username,
email: infop.email,
};
save_event_writer.send(SaveEvent {
value: SaveEventValue::User(cfg_user.into_inner().clone()),
});
login_state.set(LoginState::None).unwrap();
menu_state.set(MenuState::AccountLoggedIn).unwrap();
}
ResponseUserInfoP::Error { error } => {
console.send(PrintConsoleLine::new(format!(
"Something went wrong with getting the user information after logging in, got error: '{}'", error
).into()));
login_state.set(LoginState::None).unwrap();
menu_state.set(MenuState::AccountLoggedIn).unwrap();
}
}
}
ResponseToken::Error { error } => {
inputs.error = error;
login_state.set(LoginState::Input).unwrap();
}
}
// Remove the task, since it's done now
commands.entity(entity).remove::<LoginCall>();
commands.entity(entity).despawn_recursive();
}
}