DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

579656c6af68146d086a69a844b68e01c5fe6bfb — Jonni Liljamo 1 year, 9 months ago f2de86d
feat(client, server, shared): implement cookie refreshing
M README.md => README.md +0 -9
@@ 5,15 5,6 @@ A multiplayer deck building game.


## **Current major issues**
### **Session cookie refreshing**
Currently, the cookie is refreshed on every single action which requires\
session auth.\
Okay, that seems pretty normal.\
So, we just save the new one to the `global.user_to_session_map` hashmap,\
and just send an event to the client with the new one, so they can update\
it in the clients presistent storage, right? This can happen automatically\
in the background.

### **Quite a few unwraps in use**
All should be handled, with sane error responses.


M client/src/plugins/networking/systems/events/receive/mod.rs => client/src/plugins/networking/systems/events/receive/mod.rs +6 -2
@@ 8,8 8,8 @@

use bevy::prelude::*;
use laurelin_shared::server::{
    channels::{AfterAuthChannel, DataRequestChannel},
    messages::{AfterAuth, DataRequestResponse, DataRequestType},
    channels::{AfterAuthChannel, CookieRefreshChannel, DataRequestChannel},
    messages::{AfterAuth, CookieRefresh, DataRequestResponse, DataRequestType},
};
use naia_bevy_client::{
    events::{ClientTickEvent, ConnectEvent, DisconnectEvent, MessageEvents, RejectEvent},


@@ 77,6 77,10 @@ pub fn message_events(
            commands.insert_resource(NextState(Some(MenuState::Menu)));
        }

        for cr_message in events.read::<CookieRefreshChannel, CookieRefresh>() {
            cfg_user.cookie = cr_message.cookie;
        }

        for response in events.read::<DataRequestChannel, DataRequestResponse>() {
            match DataRequestType::from_u8(&response.r#type) {
                DataRequestType::GameCreate => {

M server/src/systems/event/message/mod.rs => server/src/systems/event/message/mod.rs +40 -10
@@ 6,14 6,17 @@
 * See LICENSE for licensing information.
 */

use bevy_ecs::{event::EventReader, system::Res};
use bevy_ecs::{
    event::EventReader,
    system::{Res, ResMut},
};
use laurelin_shared::{
    api::game::{
        all_forming, create, my_games, ResponseAllForming, ResponseCreateGame, ResponseMyGames,
    },
    server::{
        channels::DataRequestChannel,
        messages::{DataRequest, DataRequestResponse, DataRequestType},
        channels::{CookieRefreshChannel, DataRequestChannel},
        messages::{CookieRefresh, DataRequest, DataRequestResponse, DataRequestType},
    },
};
use naia_bevy_server::{events::MessageEvents, Server};


@@ 24,7 27,7 @@ pub(crate) fn message_events(
    mut ev: EventReader<MessageEvents>,
    mut server: Server,
    config: Res<Config>,
    global: Res<Global>,
    mut global: ResMut<Global>,
) {
    for events in ev.iter() {
        for (user_key, request) in events.read::<DataRequestChannel, DataRequest>() {


@@ 32,8 35,8 @@ pub(crate) fn message_events(
                DataRequestType::GameCreate => {
                    // TODO: handle
                    let cookie = global.user_to_session_map.get(&user_key).unwrap();
                    let response = create(&config.api_address, &cookie);
                    let json = match response {
                    let wrapped = create(&config.api_address, &cookie);
                    let json = match wrapped.response {
                        ResponseCreateGame::Error(err) => serde_json::to_string(&err).unwrap(), // TODO: handle
                        ResponseCreateGame::Valid(result) => {
                            serde_json::to_string(&result).unwrap() // TODO: handle


@@ 43,12 46,21 @@ pub(crate) fn message_events(
                        &user_key,
                        &DataRequestResponse::new(request.r#type, &json),
                    );

                    // update cookie
                    global
                        .user_to_session_map
                        .insert(user_key, wrapped.cookie.clone());
                    server.send_message::<CookieRefreshChannel, CookieRefresh>(
                        &user_key,
                        &CookieRefresh::new(&wrapped.cookie),
                    );
                }
                DataRequestType::GameAllForming => {
                    // TODO: handle
                    let cookie = global.user_to_session_map.get(&user_key).unwrap();
                    let response = all_forming(&config.api_address, &cookie);
                    let json = match response {
                    let wrapped = all_forming(&config.api_address, &cookie);
                    let json = match wrapped.response {
                        ResponseAllForming::Error(err) => serde_json::to_string(&err).unwrap(), // TODO: handle
                        ResponseAllForming::Valid(result) => {
                            serde_json::to_string(&result).unwrap() // TODO: handle


@@ 58,12 70,21 @@ pub(crate) fn message_events(
                        &user_key,
                        &DataRequestResponse::new(request.r#type, &json),
                    );

                    // update cookie
                    global
                        .user_to_session_map
                        .insert(user_key, wrapped.cookie.clone());
                    server.send_message::<CookieRefreshChannel, CookieRefresh>(
                        &user_key,
                        &CookieRefresh::new(&wrapped.cookie),
                    );
                }
                DataRequestType::GameMyGames => {
                    // TODO: handle
                    let cookie = global.user_to_session_map.get(&user_key).unwrap();
                    let response = my_games(&config.api_address, &cookie);
                    let json = match response {
                    let wrapped = my_games(&config.api_address, &cookie);
                    let json = match wrapped.response {
                        ResponseMyGames::Error(err) => serde_json::to_string(&err).unwrap(), // TODO: handle
                        ResponseMyGames::Valid(result) => {
                            serde_json::to_string(&result).unwrap() // TODO: handle


@@ 73,6 94,15 @@ pub(crate) fn message_events(
                        &user_key,
                        &DataRequestResponse::new(request.r#type, &json),
                    );

                    // update cookie
                    global
                        .user_to_session_map
                        .insert(user_key, wrapped.cookie.clone());
                    server.send_message::<CookieRefreshChannel, CookieRefresh>(
                        &user_key,
                        &CookieRefresh::new(&wrapped.cookie),
                    );
                }
            }
        }

M shared/src/api/game/all_forming.rs => shared/src/api/game/all_forming.rs +12 -3
@@ 9,7 9,7 @@
use reqwest::{self, header::COOKIE};
use serde::{Deserialize, Serialize};

use crate::{error::api::APIError, types::game::Game};
use crate::{api::macros::extract_cookie, error::api::APIError, types::game::Game};

pub type ResultAllForming = Vec<Game>;



@@ 20,7 20,13 @@ pub enum ResponseAllForming {
    Valid(ResultAllForming),
}

pub fn all_forming(api_address: &String, cookie: &String) -> ResponseAllForming {
#[derive(Deserialize)]
pub struct ResponseAllFormingWrapper {
    pub response: ResponseAllForming,
    pub cookie: String,
}

pub fn all_forming(api_address: &String, cookie: &String) -> ResponseAllFormingWrapper {
    let client = reqwest::blocking::Client::new();

    let resp = client


@@ 29,5 35,8 @@ pub fn all_forming(api_address: &String, cookie: &String) -> ResponseAllForming 
        .send()
        .unwrap();

    resp.json().unwrap()
    ResponseAllFormingWrapper {
        cookie: extract_cookie!(resp),
        response: resp.json().unwrap(),
    }
}

M shared/src/api/game/create.rs => shared/src/api/game/create.rs +12 -3
@@ 9,7 9,7 @@
use reqwest::{self, header::COOKIE};
use serde::{Deserialize, Serialize};

use crate::{error::api::APIError, types::game::Game};
use crate::{api::macros::extract_cookie, error::api::APIError, types::game::Game};

#[derive(Serialize, Deserialize)]
#[serde(untagged)]


@@ 18,7 18,13 @@ pub enum ResponseCreateGame {
    Valid(Game),
}

pub fn create(api_address: &String, cookie: &String) -> ResponseCreateGame {
#[derive(Deserialize)]
pub struct ResponseCreateGameWrapper {
    pub response: ResponseCreateGame,
    pub cookie: String,
}

pub fn create(api_address: &String, cookie: &String) -> ResponseCreateGameWrapper {
    let client = reqwest::blocking::Client::new();

    let resp = client


@@ 27,5 33,8 @@ pub fn create(api_address: &String, cookie: &String) -> ResponseCreateGame {
        .send()
        .unwrap();

    resp.json().unwrap()
    ResponseCreateGameWrapper {
        cookie: extract_cookie!(resp),
        response: resp.json().unwrap(),
    }
}

M shared/src/api/game/mygames.rs => shared/src/api/game/mygames.rs +12 -3
@@ 9,7 9,7 @@
use reqwest::{self, header::COOKIE};
use serde::{Deserialize, Serialize};

use crate::{error::api::APIError, types::game::Game};
use crate::{api::macros::extract_cookie, error::api::APIError, types::game::Game};

pub type ResultMyGames = Vec<Game>;



@@ 20,7 20,13 @@ pub enum ResponseMyGames {
    Valid(ResultMyGames),
}

pub fn my_games(api_address: &String, cookie: &String) -> ResponseMyGames {
#[derive(Deserialize)]
pub struct ResponseMyGamesWrapper {
    pub response: ResponseMyGames,
    pub cookie: String,
}

pub fn my_games(api_address: &String, cookie: &String) -> ResponseMyGamesWrapper {
    let client = reqwest::blocking::Client::new();

    let resp = client


@@ 29,5 35,8 @@ pub fn my_games(api_address: &String, cookie: &String) -> ResponseMyGames {
        .send()
        .unwrap();

    resp.json().unwrap()
    ResponseMyGamesWrapper {
        cookie: extract_cookie!(resp),
        response: resp.json().unwrap(),
    }
}

M shared/src/server/channels.rs => shared/src/server/channels.rs +7 -0
@@ 14,6 14,9 @@ use naia_bevy_shared::{
pub struct AfterAuthChannel;

#[derive(Channel)]
pub struct CookieRefreshChannel;

#[derive(Channel)]
pub struct DataRequestChannel;

pub struct ChannelsPlugin;


@@ 25,6 28,10 @@ impl ProtocolPlugin for ChannelsPlugin {
                ChannelDirection::ServerToClient,
                ChannelMode::UnorderedReliable(ReliableSettings::default()),
            )
            .add_channel::<CookieRefreshChannel>(
                ChannelDirection::ServerToClient,
                ChannelMode::UnorderedReliable(ReliableSettings::default()),
            )
            .add_channel::<DataRequestChannel>(
                ChannelDirection::Bidirectional,
                ChannelMode::OrderedReliable(ReliableSettings::default()),

A shared/src/server/messages/cookierefresh.rs => shared/src/server/messages/cookierefresh.rs +22 -0
@@ 0,0 1,22 @@
/*
 * This file is part of laurelin/shared
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use naia_bevy_shared::Message;

#[derive(Message)]
pub struct CookieRefresh {
    pub cookie: String,
}

impl CookieRefresh {
    pub fn new(cookie: &str) -> Self {
        Self {
            cookie: cookie.to_string(),
        }
    }
}

M shared/src/server/messages/mod.rs => shared/src/server/messages/mod.rs +4 -0
@@ 11,6 11,9 @@ use naia_bevy_shared::{Protocol, ProtocolPlugin};
mod auth;
pub use auth::{AfterAuth, Auth};

mod cookierefresh;
pub use cookierefresh::CookieRefresh;

mod datarequest;
pub use datarequest::{DataRequest, DataRequestResponse, DataRequestType};



@@ 21,6 24,7 @@ impl ProtocolPlugin for MessagesPlugin {
        protocol
            .add_message::<Auth>()
            .add_message::<AfterAuth>()
            .add_message::<CookieRefresh>()
            .add_message::<datarequest::DataRequest>()
            .add_message::<datarequest::DataRequestResponse>();
    }