167 lines
6.8 KiB
Rust
167 lines
6.8 KiB
Rust
mod commands;
|
|
mod crdt;
|
|
#[cfg(feature = "dev-server")]
|
|
mod dev_server;
|
|
mod node;
|
|
mod protocol;
|
|
mod storage;
|
|
mod verification;
|
|
|
|
use std::collections::{HashMap, HashSet};
|
|
use std::sync::Arc;
|
|
use tokio::sync::Mutex;
|
|
|
|
use crate::crdt::CrdtEngine;
|
|
use crate::protocol::identity::DuskIdentity;
|
|
use crate::protocol::messages::VoiceParticipant;
|
|
use crate::storage::DiskStorage;
|
|
|
|
// shared application state accessible from all tauri commands
|
|
pub struct AppState {
|
|
pub identity: Arc<Mutex<Option<DuskIdentity>>>,
|
|
pub crdt_engine: Arc<Mutex<CrdtEngine>>,
|
|
pub storage: Arc<DiskStorage>,
|
|
pub node_handle: Arc<Mutex<Option<node::NodeHandle>>>,
|
|
// tracks which peers are in which voice channels, keyed by "community_id:channel_id"
|
|
pub voice_channels: Arc<Mutex<HashMap<String, Vec<VoiceParticipant>>>>,
|
|
// communities joined via invite that require initial role hardening
|
|
pub pending_join_role_guard: Arc<Mutex<HashSet<String>>>,
|
|
}
|
|
|
|
impl AppState {
|
|
pub fn new() -> Self {
|
|
let storage = Arc::new(DiskStorage::new().expect("failed to initialize storage"));
|
|
let mut engine = CrdtEngine::new(storage.clone());
|
|
|
|
// restore persisted communities from disk so data survives restarts
|
|
if let Err(e) = engine.load_all() {
|
|
log::warn!("failed to load persisted communities: {}", e);
|
|
}
|
|
|
|
let crdt_engine = Arc::new(Mutex::new(engine));
|
|
|
|
Self {
|
|
identity: Arc::new(Mutex::new(None)),
|
|
crdt_engine,
|
|
storage,
|
|
node_handle: Arc::new(Mutex::new(None)),
|
|
voice_channels: Arc::new(Mutex::new(HashMap::new())),
|
|
pending_join_role_guard: Arc::new(Mutex::new(HashSet::new())),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
// load .env from the project root so config like DUSK_RELAY_ADDR is available
|
|
dotenvy::dotenv().ok();
|
|
|
|
tauri::Builder::default()
|
|
.plugin(tauri_plugin_shell::init())
|
|
.plugin(tauri_plugin_notification::init())
|
|
.manage(AppState::new())
|
|
.setup(|app| {
|
|
// grant microphone/camera permissions on linux webkitgtk
|
|
// without this, getUserMedia is denied by default
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
use tauri::Manager;
|
|
if let Some(window) = app.get_webview_window("main") {
|
|
window
|
|
.with_webview(|webview| {
|
|
use webkit2gtk::PermissionRequestExt;
|
|
use webkit2gtk::WebViewExt;
|
|
let wv = webview.inner();
|
|
wv.connect_permission_request(|_webview, request| {
|
|
request.allow();
|
|
true
|
|
});
|
|
})
|
|
.ok();
|
|
}
|
|
}
|
|
// launch the dev http server when compiled with the dev-server feature
|
|
// available at http://127.0.0.1:3333 (or DUSK_DEV_PORT)
|
|
#[cfg(feature = "dev-server")]
|
|
{
|
|
use tauri::Manager;
|
|
let state = app.state::<AppState>();
|
|
let dev_state = dev_server::DevState {
|
|
identity: std::sync::Arc::clone(&state.identity),
|
|
crdt_engine: std::sync::Arc::clone(&state.crdt_engine),
|
|
storage: std::sync::Arc::clone(&state.storage),
|
|
node_handle: std::sync::Arc::clone(&state.node_handle),
|
|
voice_channels: std::sync::Arc::clone(&state.voice_channels),
|
|
pending_join_role_guard: std::sync::Arc::clone(&state.pending_join_role_guard),
|
|
app_handle: app.handle().clone(),
|
|
};
|
|
tauri::async_runtime::spawn(dev_server::start(dev_state));
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
.invoke_handler(tauri::generate_handler![
|
|
commands::identity::has_identity,
|
|
commands::identity::load_identity,
|
|
commands::identity::create_identity,
|
|
commands::identity::update_display_name,
|
|
commands::identity::update_profile,
|
|
commands::identity::load_settings,
|
|
commands::identity::save_settings,
|
|
commands::identity::get_known_peers,
|
|
commands::identity::search_directory,
|
|
commands::identity::get_friends,
|
|
commands::identity::add_friend,
|
|
commands::identity::remove_friend,
|
|
commands::identity::discover_global_peers,
|
|
commands::identity::set_relay_discoverable,
|
|
commands::identity::set_relay_address,
|
|
commands::identity::reset_identity,
|
|
commands::identity::cache_avatar_icon,
|
|
commands::chat::send_message,
|
|
commands::chat::get_messages,
|
|
commands::chat::send_typing,
|
|
commands::chat::start_node,
|
|
commands::chat::stop_node,
|
|
commands::chat::check_internet_connectivity,
|
|
commands::chat::broadcast_presence,
|
|
commands::community::create_community,
|
|
commands::community::join_community,
|
|
commands::community::leave_community,
|
|
commands::community::get_communities,
|
|
commands::community::create_channel,
|
|
commands::community::get_channels,
|
|
commands::community::get_members,
|
|
commands::community::delete_message,
|
|
commands::community::kick_member,
|
|
commands::community::generate_invite,
|
|
commands::community::reorder_channels,
|
|
commands::community::create_category,
|
|
commands::community::get_categories,
|
|
commands::community::update_community,
|
|
commands::community::update_channel,
|
|
commands::community::delete_channel,
|
|
commands::community::delete_category,
|
|
commands::community::set_member_role,
|
|
commands::community::transfer_ownership,
|
|
commands::voice::join_voice_channel,
|
|
commands::voice::leave_voice_channel,
|
|
commands::voice::update_voice_media_state,
|
|
commands::voice::send_voice_sdp,
|
|
commands::voice::send_voice_ice_candidate,
|
|
commands::voice::get_voice_participants,
|
|
commands::dm::send_dm,
|
|
commands::dm::get_dm_messages,
|
|
commands::dm::search_dm_messages,
|
|
commands::dm::get_dm_conversations,
|
|
commands::dm::mark_dm_read,
|
|
commands::dm::delete_dm_conversation,
|
|
commands::dm::send_dm_typing,
|
|
commands::dm::open_dm_conversation,
|
|
commands::gif::search_gifs,
|
|
commands::gif::get_trending_gifs,
|
|
])
|
|
.run(tauri::generate_context!())
|
|
.expect("error while running dusk");
|
|
}
|