pub mod schema;
use crate::schema::*;
use anyhow::Error;
use serde::{Deserialize, Serialize};
pub use serde_json::{Map, Value};
use std::fmt::{self, Display};
use std::process::ExitStatus;
use std::thread::JoinHandle;
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
pub enum Player {
P1,
P2,
}
impl Display for Player {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Player::*;
match self {
P1 => write!(f, "P1"),
P2 => write!(f, "P2"),
}
}
}
impl From<Player> for u8 {
fn from(player: Player) -> Self {
use Player::*;
match player {
P1 => 0,
P2 => 1,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Request {
pub request_id: u32,
#[serde(flatten)]
pub body: RequestBody,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum RequestBody {
Ping,
GetGameList,
GetGameListFromFs,
GetGame(String), DownloadGame(String), DownloadIcon(String), DownloadBanner(String),
GetTagList,
GetTag(String), GetGameListFromTag(String),
GetUser(String),
SetProduction(bool),
LaunchGame(String),
GetNfcTag(Player), GetNfcUser(String), }
impl RequestBody {
pub fn variants() -> Vec<Self> {
vec![
Self::Ping,
Self::GetGameList,
Self::GetGameListFromFs,
Self::GetGame(String::new()),
Self::DownloadGame(String::new()),
Self::DownloadIcon(String::new()),
Self::DownloadBanner(String::new()),
Self::GetTagList,
Self::GetTag(String::new()),
Self::GetGameListFromTag(String::new()),
Self::SetProduction(false),
Self::LaunchGame(String::new()),
Self::GetNfcTag(Player::P1),
Self::GetNfcUser(String::new()),
]
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Response {
pub request_id: u32,
#[serde(flatten)]
pub body: ResponseBody,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum ResponseBody {
Pong,
Ok,
Err(String),
GameList(Vec<DevcadeGame>),
Game(DevcadeGame),
TagList(Vec<Tag>),
Tag(Tag),
User(User),
NfcTag(Option<String>),
NfcUser(Map<String, Value>),
#[serde(skip)]
InternalGame(JoinHandle<ExitStatus>),
}
impl From<Error> for ResponseBody {
fn from(error: Error) -> Self {
Self::Err(error.to_string())
}
}
impl ResponseBody {
pub fn variants() -> Vec<Self> {
vec![
Self::Pong,
Self::Ok,
Self::Err(String::new()),
Self::GameList(Vec::new()),
Self::Game(DevcadeGame::default()),
Self::TagList(Vec::new()),
Self::Tag(Tag::default()),
Self::InternalGame(std::thread::spawn(|| std::process::exit(0))),
Self::NfcTag(None),
Self::NfcUser(Map::default()),
]
}
}
impl Display for RequestBody {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Self::Ping => write!(f, "Ping"),
Self::GetGameList => write!(f, "Get Game List"),
Self::GetGameListFromFs => write!(f, "Get Game List From Filesystem"),
Self::GetGame(game_id) => {
write!(f, "Get Game object with id '{game_id}'")
}
Self::DownloadGame(game_id) => {
write!(f, "Download game with id '{game_id}'")
}
Self::DownloadIcon(game_id) => {
write!(f, "Download icon with id '{game_id}'")
}
Self::DownloadBanner(game_id) => {
write!(f, "Download banner with id '{game_id}'")
}
Self::LaunchGame(game_id) => {
write!(f, "Launch game with id '{game_id}'")
}
Self::SetProduction(prod) => {
write!(
f,
"Set API to '{}'",
if *prod { "production" } else { "development" }
)
}
Self::GetTagList => write!(f, "Get Tag List"),
Self::GetTag(tag_name) => write!(f, "Get Tag with name '{tag_name}'"),
Self::GetGameListFromTag(tag_name) => {
write!(f, "Get Game List from Tag with name '{tag_name}'")
}
Self::GetUser(uid) => write!(f, "Get User with id '{uid}'"),
Self::GetNfcTag(player) => {
write!(f, "Get NFC tags for player '{player}'")
}
Self::GetNfcUser(association_id) => {
write!(f, "Get NFC users for association ID '{association_id}'")
}
}
}
}
impl Display for Request {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let id = self.request_id;
let body = &self.body;
write!(f, "[{id:9}] {body}")
}
}
impl Display for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let id = self.request_id;
let body = &self.body;
write!(f, "[{id:9}] {body}")
}
}
impl Display for ResponseBody {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Self::Pong => write!(f, "Pong"),
Self::Ok => write!(f, "Ok"),
Self::Err(err) => write!(f, "Err: {err}"),
Self::GameList(games) => {
write!(f, "Got game list with {} games", games.len())
}
Self::Game(DevcadeGame { id, .. }) => {
write!(f, "Downloaded game with id '{}'", id)
}
Self::InternalGame(_) => write!(f, "Launched game"),
Self::TagList(tags) => {
write!(f, "Got tag list with {} tags", tags.len())
}
Self::Tag(Tag { name, .. }) => write!(f, "Got tag with name '{name}'"),
Self::User(User { id, .. }) => write!(f, "Got user with id '{id}'"),
Self::NfcTag(tag_id) => {
write!(f, "Got NFC tag ID '{tag_id:?}'")
}
Self::NfcUser(user) => {
write!(f, "Got NFC user '{user:?}'")
}
}
}
}