feat: added download and upload commands

redid actions to better support different clients
This commit is contained in:
Andrew Rioux
2025-03-03 20:03:04 -05:00
parent e0bd5c3b06
commit 7f9ea12b6a
21 changed files with 401 additions and 88 deletions

View File

@@ -242,27 +242,35 @@ pub fn InstancesView() -> impl IntoView {
let (done_with_scrolling, set_done_with_scrolling) = signal(false);
#[cfg(not(feature = "ssr"))]
let (web_socket, rebuild_websocket) = signal(use_websocket::<
BeaconClientMessage,
BeaconViewEvent,
codee::string::JsonSerdeCodec,
>("/api/subscribe/listener"));
let user = expect_context::<ReadSignal<Option<crate::users::User>>>();
#[cfg(not(feature = "ssr"))]
(web_socket.get_untracked().send)(&BeaconClientMessage::LoadHistorical(0));
let web_socket = Memo::new_with_compare(
move |_| {
// subscribe to changes in the user, so that if a user signs it is possible
// to recreate the websocket with a new session ID
user.get();
#[cfg(not(feature = "ssr"))]
Effect::new(move |_| {
let user = expect_context::<ReadSignal<Option<crate::users::User>>>();
user.with(move |_| {
rebuild_websocket(use_websocket::<
leptos::logging::log!("Recreating socket");
use_websocket::<
BeaconClientMessage,
BeaconViewEvent,
codee::string::JsonSerdeCodec,
>(&format!(
"/api/subscribe/beacon/{}",
instance_id.get().expect("could not extract ID from URL").id)
));
)
},
|_, _| true
);
#[cfg(not(feature = "ssr"))]
Effect::new(move |_| {
web_socket.get().ready_state.with(move |state| {
if *state == leptos_use::core::ConnectionReadyState::Open {
update_line_items(VecDeque::new());
(web_socket.get_untracked().send)(&BeaconClientMessage::LoadHistorical(0));
}
});
});
@@ -409,7 +417,7 @@ pub fn InstancesView() -> impl IntoView {
{format!("command {command_id} finished executing at {result_date}")}<br/>
</div>
<div class="instance-hist-body">
{action.render_data(action_result)}
{action.render_composite_action(action_result)}
</div>
</div>
}),

View File

@@ -183,11 +183,13 @@ pub async fn start_listener(listener_id: i64) -> Result<(), ServerFnError> {
));
}
let target_file_path = expect_context::<std::path::PathBuf>();
sparse_handler::start_listener(
expect_context(),
listener_id,
expect_context(),
expect_context()
expect_context(),
target_file_path,
).await?;
Ok(())

View File

@@ -12,6 +12,7 @@ use leptos_axum::{generate_route_list, LeptosRoutes};
use serde::Deserialize;
use sqlx::sqlite::SqlitePool;
use tokio::signal;
use tokio_util::io::ReaderStream;
use sparse_actions::version::Version;
use sparse_server::app::*;
@@ -101,6 +102,7 @@ pub struct AppState {
leptos_options: leptos::config::LeptosOptions,
beacon_listeners: sparse_handler::BeaconListenerMap,
beacon_event_broadcast: tokio::sync::broadcast::Sender<sparse_handler::BeaconEvent>,
file_store: PathBuf,
}
async fn get_parameters_bytes(
@@ -323,6 +325,41 @@ pub async fn download_beacon_installer(
))
}
pub async fn download_file(
State(state): State<AppState>,
cookie_jar: CookieJar,
Path(file_id): Path<String>
) -> axum::response::Response {
if let Err(e) = crate::db::user::get_auth_session_inner(
state.db.clone(),
cookie_jar
).await {
tracing::warn!("Could not load user session: {e:?}");
return axum::http::StatusCode::INTERNAL_SERVER_ERROR.into_response();
}
let mut file_path = state.file_store.clone();
file_path.push(file_id);
let file = match tokio::fs::File::open(file_path).await {
Ok(f) => f,
Err(e) => {
tracing::warn!("Could not open file: {e:?}");
return axum::http::StatusCode::INTERNAL_SERVER_ERROR.into_response();
}
};
let stream = ReaderStream::new(file);
use axum::http::header;
(
[
(header::CONTENT_TYPE, "application/octet-stream".to_string())
],
axum::body::Body::from_stream(stream).into_response()
).into_response()
}
pub async fn subscribe_to_listener_events(
State(state): State<AppState>,
cookie_jar: CookieJar,
@@ -813,14 +850,16 @@ pub async fn serve_web(
sparse_handler::start_all_listeners(
beacon_listeners.clone(),
db.clone(),
beacon_event_broadcast.clone()
beacon_event_broadcast.clone(),
file_store.clone(),
).await?;
let state = AppState {
leptos_options: leptos_options.clone(),
db: db.clone(),
beacon_listeners: beacon_listeners.clone(),
beacon_event_broadcast: beacon_event_broadcast.clone()
beacon_event_broadcast: beacon_event_broadcast.clone(),
file_store: file_store.clone(),
};
let app = Router::new()
@@ -829,6 +868,7 @@ pub async fn serve_web(
get(download_beacon_installer),
)
.route("/binaries/beacon/:template_id", get(download_beacon))
.route("/binaries/files/:file_id", get(download_file))
.route(
"/api/subscribe/listener",
axum::routing::any(subscribe_to_listener_events)