Skip to content

Commit

Permalink
WiP Browse many
Browse files Browse the repository at this point in the history
  • Loading branch information
hrzlgnm committed Dec 3, 2024
1 parent aa89022 commit 962faef
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 75 deletions.
213 changes: 143 additions & 70 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,76 +41,6 @@ fn get_shared_daemon() -> SharedServiceDaemon {
Arc::new(Mutex::new(daemon))
}

#[tauri::command]
fn browse_types(window: Window, state: State<ManagedState>) {
if let Ok(mdns) = state.daemon.lock() {
let mdns_for_thread = mdns.clone();
std::thread::spawn(move || {
let receiver = mdns_for_thread
.browse(MDNS_SD_META_SERVICE)
.expect("Failed to browse");
while let Ok(event) = receiver.recv() {
match event {
ServiceEvent::ServiceFound(_service_type, full_name) => {
log::debug!("Service type found: {}", full_name);
window
.emit(
"service-type-found",
&ServiceTypeFoundEvent {
service_type: full_name,
},
)
.expect("To emit");
}
ServiceEvent::ServiceRemoved(_service_type, full_name) => {
log::debug!("Service type removed: {}", full_name);
window
.emit(
"service-type-removed",
&ServiceTypeRemovedEvent {
service_type: full_name,
},
)
.expect("To emit");
}
ServiceEvent::SearchStopped(service_type) => {
if service_type == MDNS_SD_META_SERVICE {
break;
}
}
_ => (),
}
}
log::debug!("Browse type thread ending.");
});
}
}

#[tauri::command]
fn stop_browse(service_type: String, state: State<ManagedState>) {
if service_type.is_empty() {
return;
}
if let Ok(mdns) = state.daemon.lock() {
if let Ok(mut running_browsers) = state.running_browsers.lock() {
if running_browsers.contains(&service_type) {
mdns.stop_browse(service_type.as_str())
.expect("To stop browsing");
running_browsers.retain(|s| s != &service_type);
}
}
}
}

#[tauri::command]
fn verify(instance_fullname: String, state: State<ManagedState>) {
log::debug!("verifying {}", instance_fullname);
if let Ok(mdns) = state.daemon.lock() {
mdns.verify(instance_fullname, VERIFY_TIMEOUT)
.expect("To verify an instance");
}
}

fn from_service_info(info: &ServiceInfo) -> ResolvedService {
let mut sorted_addresses: Vec<IpAddr> = info.get_addresses().clone().drain().collect();
sorted_addresses.sort();
Expand Down Expand Up @@ -200,6 +130,147 @@ fn browse(service_type: String, window: Window, state: State<ManagedState>) {
}
}

#[tauri::command]
fn browse_types(window: Window, state: State<ManagedState>) {
if let Ok(mdns) = state.daemon.lock() {
let mdns_for_thread = mdns.clone();
std::thread::spawn(move || {
let receiver = mdns_for_thread
.browse(MDNS_SD_META_SERVICE)
.expect("Failed to browse");
while let Ok(event) = receiver.recv() {
match event {
ServiceEvent::ServiceFound(_service_type, full_name) => {
log::debug!("Service type found: {}", full_name);
window
.emit(
"service-type-found",
&ServiceTypeFoundEvent {
service_type: full_name,
},
)
.expect("To emit");
}
ServiceEvent::ServiceRemoved(_service_type, full_name) => {
log::debug!("Service type removed: {}", full_name);
window
.emit(
"service-type-removed",
&ServiceTypeRemovedEvent {
service_type: full_name.clone(),
},
)
.expect("To emit");
}
ServiceEvent::SearchStopped(service_type) => {
if service_type == MDNS_SD_META_SERVICE {
break;
}
}
_ => (),
}
}
log::debug!("Browse type thread ending.");
});
}
}

#[tauri::command]
fn stop_browse(service_type: String, state: State<ManagedState>) {
if service_type.is_empty() {
return;
}
if let Ok(mdns) = state.daemon.lock() {
if let Ok(mut running_browsers) = state.running_browsers.lock() {
if running_browsers.contains(&service_type) {
mdns.stop_browse(service_type.as_str())
.expect("To stop browsing");
running_browsers.retain(|s| s != &service_type);
}
}
}
}

#[tauri::command]
fn verify(instance_fullname: String, state: State<ManagedState>) {
log::debug!("verifying {}", instance_fullname);
if let Ok(mdns) = state.daemon.lock() {
mdns.verify(instance_fullname, VERIFY_TIMEOUT)
.expect("To verify an instance");
}
}

#[tauri::command]
fn browse_many(service_types: Vec<String>, window: Window, state: State<ManagedState>) {
for service_type in service_types {
if let Ok(mdns) = state.daemon.lock() {
if let Ok(mut running_browsers) = state.running_browsers.lock() {
if !running_browsers.contains(&service_type) {
running_browsers.push(service_type.clone());
let receiver = mdns.browse(service_type.as_str()).expect("To browse");
let window = window.clone();
std::thread::spawn(move || {
while let Ok(event) = receiver.recv() {
match event {
ServiceEvent::ServiceFound(_service_type, instance_name) => {
window
.emit(
"service-found",
&ServiceFoundEvent {
instance_name,
at_ms: timestamp_millis(),
},
)
.expect("To emit");
}
ServiceEvent::SearchStarted(service_type) => {
window
.emit(
"search-started",
&SearchStartedEvent { service_type },
)
.expect("to emit");
}
ServiceEvent::ServiceResolved(info) => {
window
.emit(
"service-resolved",
&ServiceResolvedEvent {
service: from_service_info(&info),
},
)
.expect("To emit");
}
ServiceEvent::ServiceRemoved(_service_type, instance_name) => {
window
.emit(
"service-removed",
&ServiceRemovedEvent {
instance_name,
at_ms: timestamp_millis(),
},
)
.expect("To emit");
}
ServiceEvent::SearchStopped(service_type) => {
window
.emit(
"search-stopped",
&SearchStoppedEvent { service_type },
)
.expect("To emit");
break;
}
}
}
log::debug!("Browse thread for {} ending.", &service_type);
});
}
}
}
}
}

#[tauri::command]
fn send_metrics(window: Window, state: State<ManagedState>) {
if let Ok(mdns) = state.daemon.lock() {
Expand Down Expand Up @@ -478,6 +549,7 @@ pub fn run() {
app_updates::fetch_update,
app_updates::install_update,
browse,
browse_many,
browse_types,
can_auto_update,
copy_to_clipboard,
Expand All @@ -501,6 +573,7 @@ pub fn run_mobile() {
.manage(ManagedState::new())
.invoke_handler(tauri::generate_handler![
browse,
browse_many,
browse_types,
copy_to_clipboard,
is_desktop,
Expand Down
47 changes: 42 additions & 5 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async fn listen_on_metrics_event(event_writer: WriteSignal<Vec<(String, i64)>>)
}

async fn listen_on_service_type_event_result(
event_writer: WriteSignal<ServiceTypes>,
event_writer: RwSignal<ServiceTypes>,
) -> Result<(), Error> {
let found = listen::<ServiceTypeFoundEventRes>("service-type-found").await?;
let removed = listen::<ServiceTypeRemovedEventRes>("service-type-removed").await?;
Expand Down Expand Up @@ -84,7 +84,7 @@ async fn listen_on_service_type_event_result(
Ok(())
}

async fn listen_on_service_type_events(event_writer: WriteSignal<ServiceTypes>) {
async fn listen_on_service_type_events(event_writer: RwSignal<ServiceTypes>) {
log::debug!("listen on service type events");
let result = listen_on_service_type_event_result(event_writer).await;
match result {
Expand Down Expand Up @@ -156,6 +156,22 @@ async fn browse(service_type: String) {
.await;
}

#[derive(Serialize, Deserialize)]
#[allow(non_snake_case)]
struct BrowseManyArgs {
serviceTypes: Vec<String>,
}

async fn browse_many(service_types: Vec<String>) {
let _ = invoke::<()>(
"browse_many",
&BrowseManyArgs {
serviceTypes: service_types,
},
)
.await;
}

async fn stop_browse(service_type: String) {
let _ = invoke::<()>(
"stop_browse",
Expand Down Expand Up @@ -270,8 +286,11 @@ fn AutoCompleteServiceType(
#[prop(optional, into)] comp_ref: ComponentRef<AutoCompleteRef>,
) -> impl IntoView {
log::debug!("AutoCompleteServiceType");
let (service_types, set_service_types) = create_signal(ServiceTypes::new());
create_resource(move || set_service_types, listen_on_service_type_events);
let service_types = use_context::<ServiceTypesSignal>()
.expect("service_tyxpes context to exist")
.0;

create_resource(move || service_types, listen_on_service_type_events);

let service_type_options = create_memo(move |_| {
service_types
Expand Down Expand Up @@ -445,11 +464,16 @@ fn ResolvedServiceGridItem(resolved_service: ResolvedService) -> impl IntoView {
}
}

#[derive(Clone, Debug)]
pub struct ServiceTypesSignal(RwSignal<ServiceTypes>);

/// Component that allows for mdns browsing using events
#[component]
fn Browse() -> impl IntoView {
log::debug!("Browse");
let (resolved, set_resolved) = create_signal(ResolvedServices::new());
let service_types = create_rw_signal(ServiceTypes::new());
provide_context(ServiceTypesSignal(service_types));
create_resource(move || set_resolved, listen_on_resolve_events);
let is_desktop = use_context::<IsDesktopSignal>()
.expect("is_desktop context to exist")
Expand Down Expand Up @@ -484,6 +508,16 @@ fn Browse() -> impl IntoView {
browse_action.dispatch(value);
};

let browse_many_action = create_action(|input: &ServiceTypes| {
let input = input.clone();
async move { browse_many(input.clone()).await }
});

let on_browse_many_click = move |_| {
let value = service_types.get_untracked();
browse_many_action.dispatch(value);
};

let stop_browse_action = create_action(|input: &String| {
let input = input.clone();
async move { stop_browse(input.clone()).await }
Expand Down Expand Up @@ -532,7 +566,10 @@ fn Browse() -> impl IntoView {
<Button on_click=on_stop_click disabled=not_browsing>
"Stop"
</Button>
</Space>
<Button on_click=on_browse_many_click disabled=browsing>
"Browse all"
</Button>
</Space>
<Grid class="responsivegrid">
<For
each=move || resolved.get()
Expand Down

0 comments on commit 962faef

Please sign in to comment.