Skip to content

Commit

Permalink
Merge branch 'CEbbinghaus:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
jessebofill authored Oct 25, 2023
2 parents 09961a2 + 9faf1c1 commit 164eed7
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 38 deletions.
2 changes: 1 addition & 1 deletion backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion backend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "backend"
version = "0.9.3"
version = "0.9.4"
edition = "2021"
license = "GPL-2.0"
authors = ["Christopher-Robin Ebbinghaus <git@cebbinghaus.com>"]
Expand Down
11 changes: 10 additions & 1 deletion backend/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ use crate::{
use actix_web::{delete, get, post, web, HttpResponse, Responder, Result};
use serde::Deserialize;
use std::{ops::Deref, sync::Arc};
use tokio::sync::broadcast::Sender;

pub(crate) fn config(cfg: &mut web::ServiceConfig) {
cfg.service(get_current_card)
cfg.service(listen)
.service(get_current_card)
.service(get_current_card_id)
.service(get_current_card_and_games)
.service(create_card)
Expand All @@ -35,6 +37,13 @@ pub(crate) async fn health() -> impl Responder {
HttpResponse::Ok()
}

#[get("/listen")]
pub(crate) async fn listen(sender: web::Data<Sender<()>>) -> Result<impl Responder> {
sender.subscribe().recv().await.map_err(|_| Error::from_str("Unable to retrieve update"))?;
Ok(HttpResponse::Ok())
}


#[get("/ListCardsWithGames")]
pub(crate) async fn list_cards_with_games(datastore: web::Data<Arc<Store>>) -> impl Responder {
web::Json(datastore.list_cards_with_games())
Expand Down
11 changes: 8 additions & 3 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use err::Error;
use futures::{pin_mut, select, FutureExt};
use once_cell::sync::Lazy;
use simplelog::LevelFilter;
use tokio::sync::broadcast::{self, Sender};
use std::path::PathBuf;
use std::process::exit;
use std::sync::Arc;
Expand All @@ -39,7 +40,7 @@ pub fn init() -> Result<(), ::log::SetLoggerError> {

type MainResult = Result<(), Error>;

async fn run_server(datastore: Arc<Store>) -> MainResult {
async fn run_server(datastore: Arc<Store>, sender: Sender<()>) -> MainResult {
// let log_filepath = format!("/tmp/{}.log", PACKAGE_NAME);
// WriteLogger::init(
// #[cfg(debug_assertions)]
Expand All @@ -58,6 +59,7 @@ async fn run_server(datastore: Arc<Store>) -> MainResult {
info!("Starting HTTP server...");

HttpServer::new(move || {

let cors = Cors::default()
.allow_any_header()
.allow_any_method()
Expand All @@ -68,6 +70,7 @@ async fn run_server(datastore: Arc<Store>) -> MainResult {
.wrap(cors)
// .app_data(web::Data::new(api::AppState{datastore: datastore.clone()}))
.app_data(web::Data::new(datastore.clone()))
.app_data(web::Data::new(sender.clone()))
.configure(config)
})
.workers(1)
Expand Down Expand Up @@ -119,9 +122,11 @@ async fn main() {

info!("Starting Program...");

let server_future = run_server(store.clone()).fuse();
let (txtx, _) = broadcast::channel::<()>(1);

let server_future = run_server(store.clone(), txtx.clone()).fuse();

let watch_future = start_watch(store.clone()).fuse();
let watch_future = start_watch(store.clone(), txtx.clone()).fuse();

pin_mut!(server_future, watch_future);

Expand Down
25 changes: 23 additions & 2 deletions backend/src/watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::collections::hash_map::DefaultHasher;
use std::fs::DirEntry;
use std::hash::{Hash, Hasher};
use std::{borrow::Borrow, collections::HashMap, fs, sync::Arc, time::Duration};
use tokio::sync::broadcast::Sender;
use tokio::time::interval;

const STEAM_LIB_FILE: &'static str = "/run/media/mmcblk0p1/libraryfolder.vdf";
Expand Down Expand Up @@ -120,19 +121,31 @@ fn read_msd_directory(datastore: &Store) -> Result<(), Error> {
Ok(())
}

pub async fn start_watch(datastore: Arc<Store>) -> Result<(), Error> {
pub async fn start_watch(datastore: Arc<Store>, sender: Sender<()>) -> Result<(), Error> {
let mut interval = interval(Duration::from_secs(5));

let mut changeset = ChangeSet::new();

let mut card_inserted = false;

loop {
interval.tick().await;

// No card no worries.
if !is_card_inserted() {
// The card has been removed since the last check
if card_inserted {
let _ = sender.send(());
}

card_inserted = false;
continue;
}

// was the card inserted since the last check.
let card_changed = !card_inserted;
card_inserted = true;

// There is no steam directory so it hasn't been formatted.
if !is_card_steam_formatted() {
continue;
Expand All @@ -148,7 +161,13 @@ pub async fn start_watch(datastore: Arc<Store>) -> Result<(), Error> {

// Do we have changes in the steam directory. This should only occur when something has been added/deleted
let hash = match changeset.is_changed(&cid) {
None => continue,
None => {
// A new card has been inserted but no content on it changed.
if card_changed {
let _ = sender.send(());
}
continue;
}
Some(v) => v,
};

Expand All @@ -162,5 +181,7 @@ pub async fn start_watch(datastore: Arc<Store>) -> Result<(), Error> {

// commit update
changeset.update(&cid, hash);

let _ = sender.send(());
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "microsdeck",
"version": "0.9.3",
"version": "0.9.4",
"description": "A SteamDeck plugin to track games across MicroSD cards",
"scripts": {
"build": "shx rm -rf dist && rollup -c",
Expand Down
88 changes: 67 additions & 21 deletions src/hooks/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export async function SetNameForMicroSDCard(CardId: string, Name: string) {
body: JSON.stringify({ id: CardId, name: Name }),
referrerPolicy: "unsafe-url",
})
.catch(Error => Logger.Error("There was a critical error: \"{Error}\"", { Error }));
.catch(Error => Logger.Error("There was a critical error: \"{Error}\"", { Error }));
}

export function GetCardsForGame(appId: string) {
Expand All @@ -38,35 +38,81 @@ export function GetCardsForGame(appId: string) {
}
}

export async function fetchEventPoll({signal}: {signal: AbortSignal}): Promise<boolean | undefined> {
try {
const response = await fetch(`${API_URL}/listen`, {
keepalive: true,
referrerPolicy: "unsafe-url",
signal
});

if (response.ok) {
return true;
}

Logger.Log("Poll timed out...")
return false;
} catch (error) {
Logger.Error("Lost contact with server..");
return undefined;
}
}

export async function fetchDeleteCard(card: MicroSDCard) {
await fetch(`${API_URL}/card/${card.uid}`, {
method: "DELETE",
referrerPolicy: "unsafe-url",
})
.catch(Error => Logger.Error("There was a critical error: \"{Error}\"", { Error }));
try {
await fetch(`${API_URL}/card/${card.uid}`, {
method: "DELETE",
referrerPolicy: "unsafe-url",
});
} catch (error) {
Logger.Error("There was a critical error: \"{Error}\"", { Error });
}
}

export async function fetchUpdateCard(card: MicroSDCard) {
await fetch(`${API_URL}/card/${card.uid}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(card),
referrerPolicy: "unsafe-url",
})
.catch(Error => Logger.Error("There was a critical error: \"{Error}\"", { Error }));
try {
await fetch(`${API_URL}/card/${card.uid}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(card),
referrerPolicy: "unsafe-url",
});
} catch (error) {
Logger.Error("There was a critical error: \"{Error}\"", { Error });
}
}

export async function fetchCurrentCardAndGames(): Promise<CardAndGames | undefined> {
return await fetch(`${API_URL}/current`, { referrerPolicy: "unsafe-url", })
.then(res => res.json())
.catch(Error => Logger.Error("There was a critical error: \"{Error}\"", { Error }));
try {
let result = await fetch(`${API_URL}/current`, { referrerPolicy: "unsafe-url", });

if(!result.ok) {
Logger.Warn("Fetch returned non 200 code {status} status, {statusText}", {status: result.status, statusText: result.statusText})
return undefined;
}

return await result.json();
} catch (error) {
Logger.Error("There was a critical error: \"{Error}\"", { Error });
return undefined;
}
}
export async function fetchCardsAndGames(): Promise<CardsAndGames | undefined> {
return await fetch(`${API_URL}/ListCardsWithGames`, { referrerPolicy: "unsafe-url", })
.then(res => res.json())
.catch(Error => Logger.Error("There was a critical error: \"{Error}\"", { Error }));
try {
let result = await fetch(`${API_URL}/ListCardsWithGames`, { referrerPolicy: "unsafe-url", });

if(!result.ok) {
Logger.Warn("Fetch returned non 200 code {status} status, {statusText}", {status: result.status, statusText: result.statusText})
return undefined;
}

return await result.json();
} catch (error) {
Logger.Error("There was a critical error: \"{Error}\"", { Error });
return undefined;
}
}

export function GetCardsAndGames() {
Expand Down
10 changes: 8 additions & 2 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ export default definePlugin((serverApi: ServerAPI) => {
});

const microSDeckManager = new MicroSDeckManager();
//@ts-ignore sssshhhhh
window.microSDeckManager = microSDeckManager;

//@ts-ignore ssshhhh 🤫
window.MicroSDeck = microSDeckManager;

microSDeckManager.init();

DeckyAPI.SetApi(serverApi);
Expand All @@ -186,6 +188,10 @@ export default definePlugin((serverApi: ServerAPI) => {
onDismount() {
serverApi.routerHook.removeRoute(DOCUMENTATION_PATH);
patch && serverApi.routerHook.removePatch('/library/app/:appid', patch);

//@ts-ignore
window.MicroSDeck = null;
microSDeckManager.deinit();
},
};
});
Loading

0 comments on commit 164eed7

Please sign in to comment.