260 lines
8.3 KiB
Rust
260 lines
8.3 KiB
Rust
/*
|
|
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
|
|
|
This file is part of On the Grid.
|
|
|
|
On the Grid is free software: you can redistribute it and/or modify it under the terms of the GNU
|
|
General Public License as published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
On the Grid is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
use crate::{
|
|
database::Database,
|
|
library, settings,
|
|
types::{Config, LibraryPath},
|
|
};
|
|
use async_std::channel::{Receiver, Sender};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
|
|
|
pub trait Observable<T> {
|
|
fn subscribe(&self) -> Receiver<T>;
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
pub enum CoreRequest {
|
|
Library(library::LibraryRequest),
|
|
Settings(settings::SettingsRequest),
|
|
/*
|
|
ChangeSetting(ChangeSettingRequest),
|
|
CreateGame(CreateGameRequest),
|
|
Home,
|
|
OpenConfiguration,
|
|
PlayingField,
|
|
PlayStone(PlayStoneRequest),
|
|
StartGame,
|
|
*/
|
|
}
|
|
|
|
/*
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum ChangeSettingRequest {
|
|
LibraryPath(String),
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct PlayStoneRequest {
|
|
pub column: u8,
|
|
pub row: u8,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct CreateGameRequest {
|
|
pub black_player: PlayerInfoRequest,
|
|
pub white_player: PlayerInfoRequest,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum PlayerInfoRequest {
|
|
Hotseat(HotseatPlayerRequest),
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct HotseatPlayerRequest {
|
|
pub name: String,
|
|
pub rank: Option<String>,
|
|
}
|
|
|
|
impl From<HotseatPlayerRequest> for Player {
|
|
fn from(p: HotseatPlayerRequest) -> Self {
|
|
Self {
|
|
name: p.name,
|
|
rank: p.rank.and_then(|r| Rank::try_from(r.as_ref()).ok()),
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum CoreResponse {
|
|
Library(library::LibraryResponse),
|
|
Settings(settings::SettingsResponse),
|
|
}
|
|
|
|
impl From<library::LibraryResponse> for CoreResponse {
|
|
fn from(r: library::LibraryResponse) -> Self {
|
|
Self::Library(r)
|
|
}
|
|
}
|
|
|
|
impl From<settings::SettingsResponse> for CoreResponse {
|
|
fn from(r: settings::SettingsResponse) -> Self {
|
|
Self::Settings(r)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum CoreNotification {
|
|
ConfigurationUpdated(Config),
|
|
BoardUpdated,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Core {
|
|
config: Arc<RwLock<Config>>,
|
|
// state: Arc<RwLock<AppState>>,
|
|
library: Arc<RwLock<Option<Database>>>,
|
|
subscribers: Arc<RwLock<Vec<Sender<CoreNotification>>>>,
|
|
}
|
|
|
|
impl Core {
|
|
pub fn new(config: Config) -> Self {
|
|
println!("config: {:?}", config);
|
|
|
|
let library = match config.get::<LibraryPath>() {
|
|
Some(ref path) if path.to_path_buf().exists() => {
|
|
Some(Database::open_path(path.to_path_buf()).unwrap())
|
|
}
|
|
_ => None,
|
|
};
|
|
|
|
Self {
|
|
config: Arc::new(RwLock::new(config)),
|
|
// state,
|
|
library: Arc::new(RwLock::new(library)),
|
|
subscribers: Arc::new(RwLock::new(vec![])),
|
|
}
|
|
}
|
|
|
|
pub fn get_config(&self) -> Config {
|
|
self.config.read().unwrap().clone()
|
|
}
|
|
|
|
/// Change the configuration of the Core. This function will update any relevant core
|
|
/// functions, especially the contents of the library, and it will notify any subscribed objects
|
|
/// that the configuration has changed.
|
|
///
|
|
/// It will not handle persisting the new configuration, as the backing store for the
|
|
/// configuration is not a decision for the core library.
|
|
pub async fn set_config(&self, config: Config) {
|
|
*self.config.write().unwrap() = config.clone();
|
|
|
|
// let db = library::read_library(self.config.read().unwrap().get::<LibraryPath>()).await;
|
|
let library_path = self.config.read().unwrap().get::<LibraryPath>();
|
|
if let Some(ref path) = library_path {
|
|
self.load_library(path);
|
|
}
|
|
|
|
self.notify(CoreNotification::ConfigurationUpdated(config.clone()))
|
|
.await;
|
|
}
|
|
|
|
fn load_library(&self, path: &LibraryPath) {
|
|
let db = Database::open_path(path.to_path_buf()).unwrap();
|
|
*self.library.write().unwrap() = Some(db);
|
|
}
|
|
|
|
pub fn library(&self) -> RwLockReadGuard<'_, Option<Database>> {
|
|
self.library.read().unwrap()
|
|
}
|
|
|
|
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
|
match request {
|
|
CoreRequest::Library(request) => library::handle(self, request).await.into(),
|
|
CoreRequest::Settings(request) => settings::handle(self, request).await.into(),
|
|
}
|
|
}
|
|
|
|
pub async fn notify(&self, notification: CoreNotification) {
|
|
let subscribers = self.subscribers.read().unwrap().clone();
|
|
for subscriber in subscribers {
|
|
let subscriber = subscriber.clone();
|
|
let _ = subscriber.send(notification.clone()).await;
|
|
}
|
|
}
|
|
|
|
/*
|
|
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
|
match request {
|
|
CoreRequest::ChangeSetting(request) => match request {
|
|
ChangeSettingRequest::LibraryPath(path) => {
|
|
// let mut config = self.config.write().unwrap();
|
|
// config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from(
|
|
// path,
|
|
// ))));
|
|
// CoreResponse::UpdatedConfigurationView(configuration(&config))
|
|
unimplemented!()
|
|
}
|
|
},
|
|
CoreRequest::CreateGame(create_request) => {
|
|
/*
|
|
let mut app_state = self.state.write().unwrap();
|
|
let white_player = {
|
|
match create_request.white_player {
|
|
PlayerInfoRequest::Hotseat(request) => Player::from(request),
|
|
}
|
|
};
|
|
let black_player = {
|
|
match create_request.black_player {
|
|
PlayerInfoRequest::Hotseat(request) => Player::from(request),
|
|
}
|
|
};
|
|
app_state.game = Some(GameState {
|
|
white_player,
|
|
black_player,
|
|
..GameState::default()
|
|
});
|
|
let game_state = app_state.game.as_ref().unwrap();
|
|
CoreResponse::PlayingFieldView(playing_field(game_state))
|
|
*/
|
|
unimplemented!()
|
|
}
|
|
CoreRequest::Home => {
|
|
// CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games()))
|
|
unimplemented!()
|
|
}
|
|
CoreRequest::OpenConfiguration => {
|
|
// CoreResponse::ConfigurationView(configuration(&self.config.read().unwrap()))
|
|
unimplemented!()
|
|
}
|
|
CoreRequest::PlayingField => {
|
|
// let app_state = self.state.read().unwrap();
|
|
// let game = app_state.game.as_ref().unwrap();
|
|
// CoreResponse::PlayingFieldView(playing_field(game))
|
|
unimplemented!()
|
|
}
|
|
CoreRequest::PlayStone(request) => {
|
|
// let mut app_state = self.state.write().unwrap();
|
|
// app_state.place_stone(request);
|
|
|
|
// let game = app_state.game.as_ref().unwrap();
|
|
// CoreResponse::PlayingFieldView(playing_field(game))
|
|
unimplemented!()
|
|
}
|
|
CoreRequest::StartGame => {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// pub async fn run(&self) {}
|
|
}
|
|
|
|
impl Observable<CoreNotification> for Core {
|
|
fn subscribe(&self) -> Receiver<CoreNotification> {
|
|
let mut subscribers = self.subscribers.write().unwrap();
|
|
|
|
let (sender, receiver) = async_std::channel::unbounded();
|
|
subscribers.push(sender);
|
|
|
|
receiver
|
|
}
|
|
}
|