initial commit

This commit is contained in:
Viv Lim 2022-08-28 02:33:26 -07:00
commit e8c63a120e
13 changed files with 3901 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

3663
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "mastodon-export"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bevy = { version = "0.8", default-features = false, features = ["bevy_winit", "png", "x11"] }
bevy_egui = "0.15.1"
egui = "0.18"
egui_extras = "0.18"
bevy-inspector-egui = "0.12.1"
tokio = { version = "1.12.0", features = ["full"] }
rfd = "0.8"
reqwest = "0.11"

View File

@ -0,0 +1,8 @@
use bevy::prelude::*;
use bevy_inspector_egui::Inspectable;
#[derive(Component, Inspectable)]
pub struct FailedRetrieving {
pub message: String
}

4
src/components/mod.rs Normal file
View File

@ -0,0 +1,4 @@
pub mod retrievable;
pub mod retrieving;
pub mod retrieved;
pub mod failed_retrieving;

View File

@ -0,0 +1,14 @@
use bevy::prelude::*;
use bevy_inspector_egui::Inspectable;
#[derive(Component, Inspectable)]
pub struct Retrievable {
pub target: Target
}
#[derive(Inspectable, Debug, Clone)]
pub enum Target {
Url(String)
}

View File

@ -0,0 +1,14 @@
use bevy::prelude::*;
use bevy_inspector_egui::Inspectable;
#[derive(Component, Inspectable)]
pub struct Retrieved {
pub asset: Asset
}
#[derive(Inspectable, Debug)]
pub enum Asset {
Text(String),
Bytes(Vec<u8>)
}

View File

@ -0,0 +1,24 @@
use bevy::prelude::*;
use bevy_inspector_egui::Inspectable;
use reqwest::Response;
use super::retrieved::Asset;
#[derive(Component)]
pub struct Retrieving {
pub response_recv: tokio::sync::oneshot::Receiver::<Retriever>
}
pub enum Retriever {
HttpRequest(reqwest::Result<Asset>)
}
impl Inspectable for Retrieving {
type Attributes = ();
fn ui(&mut self, ui: &mut egui::Ui, options: Self::Attributes, context: &mut bevy_inspector_egui::Context) -> bool {
ui.label("downloading...");
false
}
}

40
src/main.rs Normal file
View File

@ -0,0 +1,40 @@
use bevy::{
prelude::*, tasks::TaskPoolBuilder,
};
use bevy_egui::EguiPlugin;
use bevy_inspector_egui::{WorldInspectorPlugin, RegisterInspectable};
use components::{retrieved::Retrieved, retrieving::Retrieving, failed_retrieving::FailedRetrieving};
use systems::ui::UiState;
pub mod systems;
pub mod components;
use crate::components::retrievable::Retrievable;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(EguiPlugin)
.add_plugin(WorldInspectorPlugin::new())
.insert_resource(tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
)
.insert_resource(UiState{ url_input: "".to_string() })
.add_system(systems::ui::main_ui)
.add_system(systems::start_retrieving::start_retrieving)
.add_system(systems::unpack_retrieved::unpack_retrieved)
.add_startup_system(setup)
.register_inspectable::<Retrievable>()
.register_inspectable::<Retrieving>()
.register_inspectable::<Retrieved>()
.register_inspectable::<FailedRetrieving>()
.run();
}
fn setup(
mut commands: Commands,
) {
}

3
src/systems/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod ui;
pub mod start_retrieving;
pub mod unpack_retrieved;

View File

@ -0,0 +1,46 @@
use std::borrow::Cow;
use bevy::prelude::*;
use reqwest::Response;
use tokio::runtime::Runtime;
use crate::components::{retrievable::Retrievable, retrieving::{Retrieving, Retriever}, retrieved::{Retrieved, Asset}};
pub fn start_retrieving(
mut commands: Commands,
runtime: Res<Runtime>,
mut target_query: Query<(&mut Retrievable, Entity), (Without<Retrieving>, Without<Retrieved>)>,
){
for (retrievable, entity) in target_query.iter_mut(){
let target = retrievable.target.clone();
let (response_send, response_recv) = tokio::sync::oneshot::channel::<Retriever>();
runtime.spawn(async move {
match target {
crate::components::retrievable::Target::Url(url) => {
let response = reqwest::get(url).await;
match response {
Ok(r) => {
match r.bytes().await {
Ok(b) => {
response_send.send(Retriever::HttpRequest(Ok(Asset::Bytes(b.to_vec()))));
},
Err(e) => {
response_send.send(Retriever::HttpRequest(Err(e)));
},
}
},
Err(e) => {
response_send.send(Retriever::HttpRequest(Err(e)));
},
}
},
}
});
commands.entity(entity).insert(Retrieving {
response_recv
});
}
}

32
src/systems/ui.rs Normal file
View File

@ -0,0 +1,32 @@
use bevy::prelude::*;
use bevy_egui::EguiContext;
use crate::components::retrievable::{Retrievable, Target};
pub fn main_ui(
mut commands: Commands,
mut egui_context: ResMut<EguiContext>,
mut ui_state: ResMut<UiState>,
) {
egui::TopBottomPanel::bottom("bottom").show(egui_context.ctx_mut(), |ui| {
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui|{
ui.horizontal(|ui|{
ui.text_edit_singleline(&mut ui_state.url_input);
if ui.button("fetch").clicked() {
commands.spawn().insert(Retrievable {
target: Target::Url(ui_state.url_input.clone())
});
ui_state.url_input = "".to_string();
}
});
});
});
}
pub struct UiState {
pub url_input: String
}

View File

@ -0,0 +1,35 @@
use std::{borrow::Cow, fmt::format};
use bevy::prelude::*;
use reqwest::Response;
use tokio::{runtime::Runtime, sync::oneshot::error::TryRecvError};
use crate::components::{retrievable::Retrievable, retrieving::{Retrieving, Retriever}, retrieved::{Retrieved, Asset}, failed_retrieving::FailedRetrieving};
pub fn unpack_retrieved(
mut commands: Commands,
mut target_query: Query<(&mut Retrieving, Entity), (Without<Retrieved>, Without<FailedRetrieving>)>,
){
for (mut retrieving, entity) in target_query.iter_mut(){
match retrieving.response_recv.try_recv(){
Ok(Retriever::HttpRequest(response)) => match response {
Ok(asset) => {
commands.entity(entity).insert(Retrieved {
asset,
});
commands.entity(entity).remove::<Retrieving>();
},
Err(e) => {
commands.entity(entity).insert(FailedRetrieving {
message: format!("retrieval failed: {:?}", e)
});
commands.entity(entity).remove::<Retrieving>();
}
},
Err(TryRecvError::Empty) => (),
Err(TryRecvError::Closed) => panic!("wat"),
}
}
}