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 e82e333cc55d67860d25ef3150263720d99e37b7
parent 89a26663e4fc28f62e5681b76b40dcbee9ff73c3
5 files changed +134 -96
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,114 @@
+
use std::collections::BTreeMap;
+

+
use radicle::cob::cache::COBS_DB_FILE;
+
use radicle::identity::RepoId;
+
use radicle::node::{Handle, Node, NOTIFICATIONS_DB_FILE};
+
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::{domain, AppState};
+

+
#[tauri::command]
+
pub(crate) fn startup(app: AppHandle) -> Result<Config, Error> {
+
    let profile = radicle::Profile::load()?;
+

+
    let inbox_db = radicle_types::outbound::sqlite::Sqlite::reader(
+
        profile.node().join(NOTIFICATIONS_DB_FILE),
+
    )?;
+
    let cob_db =
+
        radicle_types::outbound::sqlite::Sqlite::reader(profile.cobs().join(COBS_DB_FILE))?;
+

+
    let inbox_service = domain::inbox::service::Service::new(inbox_db);
+
    let patch_service = domain::patch::service::Service::new(cob_db);
+

+
    app.manage(inbox_service);
+
    app.manage(patch_service);
+

+
    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,8 @@
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_types::domain;
-
use radicle_types::error::Error;
use radicle_types::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() {
@@ -25,94 +14,14 @@ pub fn run() {
    let builder = tauri::Builder::default();

    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 _ = 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.");
-
                    }
-

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

-
            Ok(())
-
        })
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_clipboard_manager::init())
        .plugin(tauri_plugin_window_state::Builder::default().build())
        .invoke_handler(tauri::generate_handler![
+
            init::startup,
+
            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";

@@ -29,7 +30,16 @@
  let unlistenNodeEvents: UnlistenFn | undefined = undefined;
  let unlistenSyncStatus: UnlistenFn | undefined = undefined;

+
  let error = $state<undefined | unknown>();
+

  onMount(async () => {
+
    try {
+
      await invoke<Config>("startup");
+
    } catch (e: unknown) {
+
      error = e;
+
      return;
+
    }
+

    if (window.__TAURI_INTERNALS__) {
      unlistenEvents = await listen("event", () => {
        // Add handler for incoming events
@@ -83,6 +93,9 @@
</script>

{#if $activeRouteStore.resource === "booting"}
+
  {#if error && typeof error === "object" && "err" in error && typeof error.err === "string"}
+
    <AuthenticationError error={error.err} />
+
  {/if}
  <!-- Don't show anything -->
{:else if $activeRouteStore.resource === "home"}
  <Repos {...$activeRouteStore.params} />