java_asm_server 0.1.3

Java bytecode reader & writer in rust
Documentation
use crate::impls::apk_load::read_apk;
use crate::server::OpenFileError;
use crate::ui::{AppContainer, DirInfo, Left};
use crate::{AccessorEnum, AccessorMut, AsmServer, ServerMut};
use log::info;
use rfd::MessageDialogResult::No;
use std::io::{Read, Seek};
use std::ops::DerefMut;
use std::time::Instant;
use tokio::runtime::Runtime;
use tokio::sync::mpsc;
use tokio::sync::mpsc::Sender;
use zip::ZipArchive;

pub enum ServerMessage {
    Progress(ProgressMessage),
}

pub struct ProgressMessage {
    // 0.0 - 1.0
    pub progress: f32,
    pub in_loading: bool,
}

pub struct FileOpenContext {
    pub path: String,
    pub start_time: Instant,
}


impl AsmServer {
    pub(crate) fn create_message_handler(
        server: &ServerMut, runtime: &Runtime, render_target: &AppContainer,
    ) -> Sender<ServerMessage> {
        let server = server.clone();
        let render_target = render_target.clone();
        let (sender, receiver) = mpsc::channel::<ServerMessage>(5);
        runtime.spawn(async move {
            let mut receiver = receiver;
            while let Some(msg) = receiver.recv().await {
                let mut server = server.lock();
                let server_ref = server.deref_mut();
                let Some(server_ref) = server_ref else { continue };
                match msg {
                    ServerMessage::Progress(progress) => {
                        server_ref.loading_state.loading_progress = progress.progress;
                        server_ref.loading_state.in_loading = progress.in_loading;
                        server_ref.on_progress_update(&render_target);
                    }
                }
            }
        });
        sender
    }

    pub(crate) async fn read_apk(
        apk_content: impl Read + Seek,
        sender: Sender<ServerMessage>,
        accessor: AccessorMut,
    ) -> Result<(), OpenFileError> {
        let zip = ZipArchive::new(apk_content)
            .map_err(OpenFileError::LoadZip)?;
        let apk_accessor = read_apk(zip, sender).await?;
        // safe unwrap, no other places in current thread will access it.
        *accessor.lock() = Some(AccessorEnum::Apk(apk_accessor));
        Ok(())
    }

    pub(crate) fn on_file_opened(
        &self,
        context: &FileOpenContext,
        render_target: AppContainer,
    ) {
        let FileOpenContext { path, start_time } = context;
        info!("open file {path} cost: {:?}", start_time.elapsed());
        self.render_to_app(render_target);
    }

    fn on_progress_update(&self, render_target: &AppContainer) {
        let current_loading_state = &self.loading_state;
        let mut top = render_target.top().lock();
        let top_mut = top.deref_mut();
        (*top_mut).loading_state = current_loading_state.clone();
    }

    fn render_to_app(&self, app: AppContainer) {
        let classes = self.read_classes();
        let start = Instant::now();
        let dir_info = DirInfo::from_classes(&classes);
        info!("resolve dir info cost: {:?}", start.elapsed());
        app.set_left(Left { root_node: dir_info, offset_key: None, hint_key: None });
    }
}