Radish alpha
r
Radicle desktop app
Radicle
Git (anonymous pull)
Log in to clone via SSH
Refactor the tauri setup hook into individual commands
Sebastian Martinez committed 1 year ago
commit e5f09330a43f6482734402d25fa787859d634cb3
parent bd7f1c78861c9e292e41b25ccaff1814eb37cbc2
5 files changed +152 -88
modified crates/radicle-tauri/src/commands.rs
@@ -2,6 +2,7 @@ pub mod auth;
pub mod cob;
pub mod diff;
pub mod inbox;
+
pub mod init;
pub mod profile;
pub mod repo;
pub mod thread;
added crates/radicle-tauri/src/commands/init.rs
@@ -0,0 +1,112 @@
+
use std::collections::BTreeMap;
+

+
use radicle::identity::RepoId;
+
use radicle::node::{Handle, Node};
+
use radicle::storage::ReadStorage;
+
use tauri::{AppHandle, Emitter, Manager};
+

+
use radicle_types::config::Config;
+
use radicle_types::error::Error;
+
use radicle_types::traits::Profile;
+
use radicle_types::AppState;
+

+
#[tauri::command]
+
pub(crate) fn load_profile(app: AppHandle) -> Result<Config, Error> {
+
    let profile = match radicle::Profile::load() {
+
        Ok(profile) => Ok::<radicle::Profile, Error>(profile),
+
        Err(radicle::profile::Error::NotFound(path)) => Err(Error::WithHint {
+
            err: anyhow::anyhow!("Radicle profile not found in '{}'.", path.display()),
+
            hint: "To setup your radicle profile, run `rad auth`.",
+
        }),
+
        Err(e) => Err(Error::WithHint {
+
            err: e.into(),
+
            hint: "Could not load radicle profile",
+
        }),
+
    }?;
+

+
    let state = AppState { profile };
+

+
    app.manage(state.clone());
+

+
    Ok(state.config())
+
}
+

+
#[tauri::command]
+
pub(crate) fn node_status_events(app: AppHandle, ctx: tauri::State<AppState>) -> Result<(), Error> {
+
    let app_handle = app.clone();
+

+
    let node = Node::new(ctx.profile.socket());
+
    let node_status = node.clone();
+

+
    tauri::async_runtime::spawn(async move {
+
        loop {
+
            let _ = app_handle.emit("node_running", node_status.is_running());
+
            tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+
        }
+
    });
+

+
    Ok(())
+
}
+

+
#[tauri::command]
+
pub(crate) fn repo_sync_events(app: AppHandle, ctx: tauri::State<AppState>) -> Result<(), Error> {
+
    let profile = &ctx.profile;
+
    let repositories = profile.storage.repositories()?;
+

+
    let app_handle = app.clone();
+
    let public_key = profile.public_key;
+

+
    let node = Node::new(profile.socket());
+
    let mut node_seeds = node.clone();
+

+
    tauri::async_runtime::spawn(async move {
+
        loop {
+
            let mut sync_status =
+
                BTreeMap::<RepoId, Option<radicle_types::cobs::repo::SyncStatus>>::new();
+
            for repo in &repositories {
+
                if let Ok(seeds) = node_seeds.seeds(repo.rid).map(Into::<Vec<_>>::into) {
+
                    if let Some(status) =
+
                        seeds
+
                            .iter()
+
                            .find_map(|radicle::node::Seed { nid, sync, .. }| {
+
                                (*nid == public_key).then_some(sync.clone())
+
                            })
+
                    {
+
                        sync_status.insert(repo.rid, status.map(Into::into));
+
                    } else {
+
                        // The local node wasn't found in the seed nodes table.
+
                        sync_status.insert(repo.rid, None);
+
                    }
+
                }
+
            }
+
            let _ = app_handle.emit("sync_status", sync_status);
+
            tokio::time::sleep(std::time::Duration::from_secs(10)).await;
+
        }
+
    });
+

+
    Ok(())
+
}
+

+
#[tauri::command]
+
pub(crate) fn node_events(app: AppHandle, ctx: tauri::State<AppState>) -> Result<(), Error> {
+
    let app_handle = app.clone();
+
    let node = Node::new(ctx.profile.socket());
+

+
    tauri::async_runtime::spawn(async move {
+
        loop {
+
            if node.is_running() {
+
                log::debug!("node: spawned node event subscription.");
+
                while let Ok(events) = node.subscribe(std::time::Duration::MAX) {
+
                    for event in events.into_iter().flatten() {
+
                        let _ = app_handle.emit("event", event);
+
                    }
+
                }
+
                log::debug!("node: event subscription loop has exited.");
+
            }
+

+
            tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+
        }
+
    });
+

+
    Ok(())
+
}
modified crates/radicle-tauri/src/lib.rs
@@ -1,19 +1,12 @@
mod commands;

-
use std::collections::BTreeMap;
-

-
use tauri::{Emitter, Manager};
-

use radicle::cob::cache::COBS_DB_FILE;
-
use radicle::identity::RepoId;
-
use radicle::node::{Handle, Node, NOTIFICATIONS_DB_FILE};
-
use radicle::storage::ReadStorage;
+
use radicle::node::NOTIFICATIONS_DB_FILE;
+
use tauri::{Listener, Manager};

-
use radicle_types::domain;
-
use radicle_types::error::Error;
-
use radicle_types::AppState;
+
use radicle_types::{domain, AppState};

-
use commands::{auth, cob, diff, inbox, profile, repo, thread};
+
use commands::{auth, cob, diff, inbox, init, profile, repo, thread};

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
@@ -26,84 +19,30 @@ pub fn run() {

    builder
        .setup(|app| {
-
            let profile: radicle::Profile = match radicle::Profile::load() {
-
                Ok(profile) => Ok::<radicle::Profile, Error>(profile),
-
                Err(radicle::profile::Error::NotFound(path)) => Err(Error::WithHint {
-
                    err: anyhow::anyhow!("Radicle profile not found in '{}'.", path.display()),
-
                    hint: "To setup your radicle profile, run `rad auth`.",
-
                }),
-
                Err(e) => Err(Error::WithHint {
-
                    err: e.into(),
-
                    hint: "Could not load radicle profile",
-
                }),
-
            }?;
-
            let public_key = profile.public_key;
-
            let repositories = profile.storage.repositories()?;
-

-
            let inbox_db = radicle_types::outbound::sqlite::Sqlite::reader(
-
                profile.node().join(NOTIFICATIONS_DB_FILE),
-
            )?;
-
            let inbox_service = domain::inbox::service::Service::new(inbox_db);
-

-
            let patch_db =
-
                radicle_types::outbound::sqlite::Sqlite::reader(profile.cobs().join(COBS_DB_FILE))?;
-
            let patch_service = domain::patch::service::Service::new(patch_db);
-

-
            let events_handler = app.handle().clone();
-
            let node_handler = app.handle().clone();
-
            let seed_handler = app.handle().clone();
-

-
            let node = Node::new(profile.socket());
-
            let node_status = node.clone();
-
            let mut node_seeds = node.clone();
-

-
            app.manage(inbox_service);
-
            app.manage(patch_service);
-
            app.manage(AppState { profile });
-

-
            tauri::async_runtime::spawn(async move {
-
                loop {
-
                    let _ = node_handler.emit("node_running", node_status.is_running());
-
                    tokio::time::sleep(std::time::Duration::from_secs(2)).await;
-
                }
-
            });
-

-
            tauri::async_runtime::spawn(async move {
-
                loop {
-
                    let mut sync_status =
-
                        BTreeMap::<RepoId, Option<radicle_types::cobs::repo::SyncStatus>>::new();
-
                    for repo in &repositories {
-
                        if let Ok(seeds) = node_seeds.seeds(repo.rid).map(Into::<Vec<_>>::into) {
-
                            if let Some(status) = seeds.iter().find_map(
-
                                |radicle::node::Seed { nid, sync, .. }| {
-
                                    (*nid == public_key).then_some(sync.clone())
-
                                },
-
                            ) {
-
                                sync_status.insert(repo.rid, status.map(Into::into));
-
                            } else {
-
                                // The local node wasn't found in the seed nodes table.
-
                                sync_status.insert(repo.rid, None);
-
                            }
-
                        }
+
            let main_window = app.get_webview_window("main").unwrap();
+
            let handle = app.handle().clone();
+

+
            main_window.listen("profile-loaded", move |_| {
+
                let ctx = handle.state::<AppState>();
+

+
                match radicle_types::outbound::sqlite::Sqlite::reader(
+
                    ctx.profile.node().join(NOTIFICATIONS_DB_FILE),
+
                ) {
+
                    Ok(inbox_db) => {
+
                        let inbox_service = domain::inbox::service::Service::new(inbox_db);
+
                        handle.manage(inbox_service);
                    }
-
                    let _ = seed_handler.emit("sync_status", sync_status);
-
                    tokio::time::sleep(std::time::Duration::from_secs(10)).await;
-
                }
-
            });
-

-
            tauri::async_runtime::spawn(async move {
-
                loop {
-
                    if node.is_running() {
-
                        log::debug!("node: spawned node event subscription.");
-
                        while let Ok(events) = node.subscribe(std::time::Duration::MAX) {
-
                            for event in events.into_iter().flatten() {
-
                                let _ = events_handler.emit("event", event);
-
                            }
-
                        }
-
                        log::debug!("node: event subscription loop has exited.");
+
                    Err(err) => log::error!("Not able to create inbox service: {}", err),
+
                };
+

+
                match radicle_types::outbound::sqlite::Sqlite::reader(
+
                    ctx.profile.cobs().join(COBS_DB_FILE),
+
                ) {
+
                    Ok(patch_db) => {
+
                        let patch_service = domain::patch::service::Service::new(patch_db);
+
                        handle.manage(patch_service);
                    }
-

-
                    tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+
                    Err(err) => log::error!("Not able to create patch service: {}", err),
                }
            });

@@ -113,6 +52,10 @@ pub fn run() {
        .plugin(tauri_plugin_clipboard_manager::init())
        .plugin(tauri_plugin_window_state::Builder::default().build())
        .invoke_handler(tauri::generate_handler![
+
            init::load_profile,
+
            init::node_status_events,
+
            init::repo_sync_events,
+
            init::node_events,
            auth::authenticate,
            repo::repo_count,
            repo::list_repos,
modified crates/radicle-types/src/lib.rs
@@ -17,6 +17,7 @@ pub mod syntax;
pub mod test;
pub mod traits;

+
#[derive(Clone)]
pub struct AppState {
    pub profile: radicle::Profile,
}
modified src/App.svelte
@@ -1,4 +1,5 @@
<script lang="ts">
+
  import type { Config } from "@bindings/config/Config";
  import type { UnlistenFn } from "@tauri-apps/api/event";
  import type { SyncStatus } from "@bindings/repo/SyncStatus";

@@ -6,7 +7,7 @@
  import { onDestroy, onMount } from "svelte";

  import { invoke } from "@app/lib/invoke";
-
  import { listen } from "@tauri-apps/api/event";
+
  import { emit, listen } from "@tauri-apps/api/event";

  import * as router from "@app/lib/router";
  import { nodeRunning, syncStatus } from "@app/lib/events";
@@ -30,6 +31,12 @@
  let unlistenSyncStatus: UnlistenFn | undefined = undefined;

  onMount(async () => {
+
    // Load profile into state before using it in other commands.
+
    await invoke<Config>("load_profile");
+
    if (window.__TAURI_INTERNALS__) {
+
      await emit("profile-loaded");
+
    }
+

    if (window.__TAURI_INTERNALS__) {
      unlistenEvents = await listen("event", () => {
        // Add handler for incoming events