Bevy+Ratutui powered Monitoring of Pico-Strike devices
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Working mDNS discovery for pico strike devices

+455 -29
+209 -8
Cargo.lock
··· 1129 1129 ] 1130 1130 1131 1131 [[package]] 1132 + name = "cordyceps" 1133 + version = "0.3.4" 1134 + source = "registry+https://github.com/rust-lang/crates.io-index" 1135 + checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" 1136 + dependencies = [ 1137 + "loom", 1138 + "tracing", 1139 + ] 1140 + 1141 + [[package]] 1132 1142 name = "cpufeatures" 1133 1143 version = "0.2.17" 1134 1144 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1303 1313 "syn 2.0.112", 1304 1314 "unicode-xid", 1305 1315 ] 1316 + 1317 + [[package]] 1318 + name = "diatomic-waker" 1319 + version = "0.2.3" 1320 + source = "registry+https://github.com/rust-lang/crates.io-index" 1321 + checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" 1306 1322 1307 1323 [[package]] 1308 1324 name = "digest" ··· 1527 1543 checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" 1528 1544 1529 1545 [[package]] 1546 + name = "futures-buffered" 1547 + version = "0.2.12" 1548 + source = "registry+https://github.com/rust-lang/crates.io-index" 1549 + checksum = "a8e0e1f38ec07ba4abbde21eed377082f17ccb988be9d988a5adbf4bafc118fd" 1550 + dependencies = [ 1551 + "cordyceps", 1552 + "diatomic-waker", 1553 + "futures-core", 1554 + "pin-project-lite", 1555 + "spin", 1556 + ] 1557 + 1558 + [[package]] 1530 1559 name = "futures-channel" 1531 1560 version = "0.3.31" 1532 1561 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1536 1565 ] 1537 1566 1538 1567 [[package]] 1568 + name = "futures-concurrency" 1569 + version = "7.6.3" 1570 + source = "registry+https://github.com/rust-lang/crates.io-index" 1571 + checksum = "0eb68017df91f2e477ed4bea586c59eaecaa47ed885a770d0444e21e62572cd2" 1572 + dependencies = [ 1573 + "fixedbitset 0.5.7", 1574 + "futures-buffered", 1575 + "futures-core", 1576 + "futures-lite", 1577 + "pin-project", 1578 + "slab", 1579 + "smallvec", 1580 + ] 1581 + 1582 + [[package]] 1539 1583 name = "futures-core" 1540 1584 version = "0.3.31" 1541 1585 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1561 1605 ] 1562 1606 1563 1607 [[package]] 1608 + name = "generator" 1609 + version = "0.8.8" 1610 + source = "registry+https://github.com/rust-lang/crates.io-index" 1611 + checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" 1612 + dependencies = [ 1613 + "cc", 1614 + "cfg-if", 1615 + "libc", 1616 + "log", 1617 + "rustversion", 1618 + "windows-link", 1619 + "windows-result", 1620 + ] 1621 + 1622 + [[package]] 1564 1623 name = "generic-array" 1565 1624 version = "0.14.7" 1566 1625 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1886 1945 version = "0.4.29" 1887 1946 source = "registry+https://github.com/rust-lang/crates.io-index" 1888 1947 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 1948 + 1949 + [[package]] 1950 + name = "loom" 1951 + version = "0.7.2" 1952 + source = "registry+https://github.com/rust-lang/crates.io-index" 1953 + checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" 1954 + dependencies = [ 1955 + "cfg-if", 1956 + "generator", 1957 + "scoped-tls", 1958 + "tracing", 1959 + "tracing-subscriber", 1960 + ] 1889 1961 1890 1962 [[package]] 1891 1963 name = "lru" ··· 2466 2538 dependencies = [ 2467 2539 "num-traits", 2468 2540 "rand 0.9.2", 2541 + ] 2542 + 2543 + [[package]] 2544 + name = "rapidhash" 2545 + version = "4.2.0" 2546 + source = "registry+https://github.com/rust-lang/crates.io-index" 2547 + checksum = "2988730ee014541157f48ce4dcc603940e00915edc3c7f9a8d78092256bb2493" 2548 + dependencies = [ 2549 + "rand 0.9.2", 2550 + "rustversion", 2469 2551 ] 2470 2552 2471 2553 [[package]] ··· 2657 2739 checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" 2658 2740 2659 2741 [[package]] 2742 + name = "sachy-fmt" 2743 + version = "0.1.0" 2744 + source = "git+https://tangled.org/sachy.dev/sachy-embed-core#07539b3e060d72b69d4c5fef8db61a10dc20541d" 2745 + 2746 + [[package]] 2747 + name = "sachy-mdns" 2748 + version = "0.1.0" 2749 + source = "git+https://tangled.org/sachy.dev/sachy-embed-core#07539b3e060d72b69d4c5fef8db61a10dc20541d" 2750 + dependencies = [ 2751 + "sachy-fmt", 2752 + "winnow", 2753 + ] 2754 + 2755 + [[package]] 2660 2756 name = "same-file" 2661 2757 version = "1.0.6" 2662 2758 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2664 2760 dependencies = [ 2665 2761 "winapi-util", 2666 2762 ] 2763 + 2764 + [[package]] 2765 + name = "scoped-tls" 2766 + version = "1.0.1" 2767 + source = "registry+https://github.com/rust-lang/crates.io-index" 2768 + checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 2667 2769 2668 2770 [[package]] 2669 2771 name = "scopeguard" ··· 2801 2903 ] 2802 2904 2803 2905 [[package]] 2906 + name = "socket2" 2907 + version = "0.6.1" 2908 + source = "registry+https://github.com/rust-lang/crates.io-index" 2909 + checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" 2910 + dependencies = [ 2911 + "libc", 2912 + "windows-sys 0.60.2", 2913 + ] 2914 + 2915 + [[package]] 2804 2916 name = "spin" 2805 2917 version = "0.10.0" 2806 2918 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2834 2946 name = "striker" 2835 2947 version = "0.1.0" 2836 2948 dependencies = [ 2949 + "async-channel", 2950 + "async-io", 2837 2951 "bevy", 2838 2952 "bevy_ratatui", 2839 2953 "color-eyre", 2840 2954 "crossterm", 2955 + "futures-concurrency", 2956 + "rapidhash", 2841 2957 "ratatui", 2958 + "sachy-mdns", 2959 + "socket2", 2842 2960 "striker-proto", 2843 2961 ] 2844 2962 ··· 3515 3633 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 3516 3634 3517 3635 [[package]] 3636 + name = "windows-result" 3637 + version = "0.4.1" 3638 + source = "registry+https://github.com/rust-lang/crates.io-index" 3639 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 3640 + dependencies = [ 3641 + "windows-link", 3642 + ] 3643 + 3644 + [[package]] 3518 3645 name = "windows-sys" 3519 3646 version = "0.45.0" 3520 3647 source = "registry+https://github.com/rust-lang/crates.io-index" 3521 3648 checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 3522 3649 dependencies = [ 3523 - "windows-targets", 3650 + "windows-targets 0.42.2", 3651 + ] 3652 + 3653 + [[package]] 3654 + name = "windows-sys" 3655 + version = "0.60.2" 3656 + source = "registry+https://github.com/rust-lang/crates.io-index" 3657 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 3658 + dependencies = [ 3659 + "windows-targets 0.53.5", 3524 3660 ] 3525 3661 3526 3662 [[package]] ··· 3538 3674 source = "registry+https://github.com/rust-lang/crates.io-index" 3539 3675 checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 3540 3676 dependencies = [ 3541 - "windows_aarch64_gnullvm", 3542 - "windows_aarch64_msvc", 3543 - "windows_i686_gnu", 3544 - "windows_i686_msvc", 3545 - "windows_x86_64_gnu", 3546 - "windows_x86_64_gnullvm", 3547 - "windows_x86_64_msvc", 3677 + "windows_aarch64_gnullvm 0.42.2", 3678 + "windows_aarch64_msvc 0.42.2", 3679 + "windows_i686_gnu 0.42.2", 3680 + "windows_i686_msvc 0.42.2", 3681 + "windows_x86_64_gnu 0.42.2", 3682 + "windows_x86_64_gnullvm 0.42.2", 3683 + "windows_x86_64_msvc 0.42.2", 3684 + ] 3685 + 3686 + [[package]] 3687 + name = "windows-targets" 3688 + version = "0.53.5" 3689 + source = "registry+https://github.com/rust-lang/crates.io-index" 3690 + checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 3691 + dependencies = [ 3692 + "windows-link", 3693 + "windows_aarch64_gnullvm 0.53.1", 3694 + "windows_aarch64_msvc 0.53.1", 3695 + "windows_i686_gnu 0.53.1", 3696 + "windows_i686_gnullvm", 3697 + "windows_i686_msvc 0.53.1", 3698 + "windows_x86_64_gnu 0.53.1", 3699 + "windows_x86_64_gnullvm 0.53.1", 3700 + "windows_x86_64_msvc 0.53.1", 3548 3701 ] 3549 3702 3550 3703 [[package]] ··· 3552 3705 version = "0.42.2" 3553 3706 source = "registry+https://github.com/rust-lang/crates.io-index" 3554 3707 checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 3708 + 3709 + [[package]] 3710 + name = "windows_aarch64_gnullvm" 3711 + version = "0.53.1" 3712 + source = "registry+https://github.com/rust-lang/crates.io-index" 3713 + checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 3555 3714 3556 3715 [[package]] 3557 3716 name = "windows_aarch64_msvc" 3558 3717 version = "0.42.2" 3559 3718 source = "registry+https://github.com/rust-lang/crates.io-index" 3560 3719 checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 3720 + 3721 + [[package]] 3722 + name = "windows_aarch64_msvc" 3723 + version = "0.53.1" 3724 + source = "registry+https://github.com/rust-lang/crates.io-index" 3725 + checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 3561 3726 3562 3727 [[package]] 3563 3728 name = "windows_i686_gnu" 3564 3729 version = "0.42.2" 3565 3730 source = "registry+https://github.com/rust-lang/crates.io-index" 3566 3731 checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 3732 + 3733 + [[package]] 3734 + name = "windows_i686_gnu" 3735 + version = "0.53.1" 3736 + source = "registry+https://github.com/rust-lang/crates.io-index" 3737 + checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 3738 + 3739 + [[package]] 3740 + name = "windows_i686_gnullvm" 3741 + version = "0.53.1" 3742 + source = "registry+https://github.com/rust-lang/crates.io-index" 3743 + checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 3567 3744 3568 3745 [[package]] 3569 3746 name = "windows_i686_msvc" ··· 3572 3749 checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 3573 3750 3574 3751 [[package]] 3752 + name = "windows_i686_msvc" 3753 + version = "0.53.1" 3754 + source = "registry+https://github.com/rust-lang/crates.io-index" 3755 + checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 3756 + 3757 + [[package]] 3575 3758 name = "windows_x86_64_gnu" 3576 3759 version = "0.42.2" 3577 3760 source = "registry+https://github.com/rust-lang/crates.io-index" 3578 3761 checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 3762 + 3763 + [[package]] 3764 + name = "windows_x86_64_gnu" 3765 + version = "0.53.1" 3766 + source = "registry+https://github.com/rust-lang/crates.io-index" 3767 + checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 3579 3768 3580 3769 [[package]] 3581 3770 name = "windows_x86_64_gnullvm" ··· 3584 3773 checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 3585 3774 3586 3775 [[package]] 3776 + name = "windows_x86_64_gnullvm" 3777 + version = "0.53.1" 3778 + source = "registry+https://github.com/rust-lang/crates.io-index" 3779 + checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 3780 + 3781 + [[package]] 3587 3782 name = "windows_x86_64_msvc" 3588 3783 version = "0.42.2" 3589 3784 source = "registry+https://github.com/rust-lang/crates.io-index" 3590 3785 checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 3786 + 3787 + [[package]] 3788 + name = "windows_x86_64_msvc" 3789 + version = "0.53.1" 3790 + source = "registry+https://github.com/rust-lang/crates.io-index" 3791 + checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 3591 3792 3592 3793 [[package]] 3593 3794 name = "winnow"
+14 -2
Cargo.toml
··· 1 1 [workspace] 2 2 resolver = "3" 3 - members = ["striker-proto"] 3 + members = [".", "striker-proto"] 4 4 5 5 [workspace.package] 6 6 authors = ["Sachy.dev <sachymetsu@tutamail.com>"] ··· 24 24 color-eyre = "0.6.5" 25 25 crossterm = "0.29.0" 26 26 ratatui = "0.30.0" 27 - bevy = { version = "0.17", default-features = false, features = ["bevy_state", "async_executor", "async-io"] } 27 + bevy = { version = "0.17", default-features = false, features = [ 28 + "bevy_state", 29 + "async_executor", 30 + "async-io", 31 + ] } 28 32 bevy_ratatui = { git = "https://tangled.org/sachy.dev/bevy_ratatui" } 29 33 striker-proto = { path = "striker-proto" } 34 + async-channel = "2.5.0" 35 + async-io = "2.6.0" 36 + futures-concurrency = "7.6.3" 37 + rapidhash = { version = "4.2.0", features = ["rand", "unsafe"] } 38 + socket2 = "0.6.1" 39 + sachy-mdns = { git = "https://tangled.org/sachy.dev/sachy-embed-core", package = "sachy-mdns", features = [ 40 + "client", 41 + ] } 30 42 31 43 [lib] 32 44 path = "src/lib.rs"
+75 -6
src/device.rs
··· 1 1 use std::net::IpAddr; 2 2 3 - use bevy::ecs::{component::Component, entity::Entity, resource::Resource}; 3 + use bevy::{ 4 + app::{Plugin, Update}, 5 + ecs::{ 6 + component::Component, 7 + entity::Entity, 8 + lifecycle::HookContext, 9 + name::Name, 10 + resource::Resource, 11 + system::{Commands, Res, ResMut}, 12 + world::DeferredWorld, 13 + }, 14 + time::Timer, 15 + }; 16 + use rapidhash::RapidHashSet; 17 + 18 + use crate::net::DiscoverResponse; 19 + 20 + #[derive(Debug, Resource, Default)] 21 + pub struct UniqueDevices(pub RapidHashSet<DeviceSocket>); 4 22 5 23 #[derive(Debug, Component)] 6 24 pub struct Device; 7 25 8 - #[derive(Debug, Component)] 9 - #[component(immutable)] 26 + #[derive(Debug, Clone, Component, Hash, PartialEq, Eq)] 27 + #[component(immutable, on_remove = on_remove_device)] 10 28 pub struct DeviceSocket { 11 - pub address: IpAddr, 29 + pub address: String, 12 30 pub port: u16, 13 31 } 14 32 33 + fn on_remove_device(mut world: DeferredWorld, context: HookContext) { 34 + let component = world 35 + .entity(context.entity) 36 + .get::<DeviceSocket>() 37 + .cloned() 38 + .unwrap(); 39 + let mut devices = world.resource_mut::<UniqueDevices>(); 40 + 41 + devices.0.remove(&component); 42 + } 43 + 15 44 #[derive(Debug, Component)] 16 45 #[component(immutable)] 17 46 pub struct StormLevel(pub u16); ··· 22 51 23 52 #[derive(Debug, Component)] 24 53 #[relationship(relationship_target = StormLevels)] 25 - pub struct Source(Entity); 54 + pub struct Source(pub Entity); 26 55 27 56 #[derive(Component, Debug)] 28 57 #[relationship_target(relationship = Source)] ··· 34 63 pub struct ConnectedDevice(pub Entity); 35 64 36 65 #[derive(Debug, Resource, Default)] 37 - pub struct SearchingDevices(pub bool); 66 + pub struct SearchingDevices { 67 + pub searching: Option<Timer>, 68 + } 69 + 70 + fn register_devices( 71 + incoming: Res<DiscoverResponse>, 72 + mut unique: ResMut<UniqueDevices>, 73 + mut commands: Commands, 74 + ) { 75 + let mut devices = Vec::new(); 76 + 77 + while let Ok(discovered) = incoming.0.try_recv() { 78 + let device_addr = DeviceSocket { 79 + address: discovered.address, 80 + port: discovered.port, 81 + }; 82 + 83 + if !unique.0.contains(&device_addr) { 84 + unique.0.insert(device_addr.clone()); 85 + devices.push(( 86 + Device, 87 + Name::new(discovered.host), 88 + device_addr, 89 + )); 90 + } 91 + } 92 + 93 + if !devices.is_empty() { 94 + commands.spawn_batch(devices); 95 + } 96 + } 97 + 98 + #[derive(Debug)] 99 + pub struct DevicePlugin; 100 + 101 + impl Plugin for DevicePlugin { 102 + fn build(&self, app: &mut bevy::app::App) { 103 + app.init_resource::<UniqueDevices>() 104 + .add_systems(Update, register_devices); 105 + } 106 + }
+40 -8
src/lib.rs
··· 1 1 mod device; 2 2 mod messages; 3 + mod net; 3 4 mod state; 4 5 5 6 use bevy::{ 6 - app::{AppExit, Plugin, PreUpdate, Update}, 7 + app::{AppExit, Plugin, PostUpdate, PreUpdate, Update}, 7 8 ecs::{ 8 9 error::Result, 9 10 message::{MessageReader, MessageWriter}, ··· 13 14 system::{Query, Res, ResMut}, 14 15 }, 15 16 state::{app::AppExtStates, condition::in_state}, 17 + time::{Real, Time, Timer}, 16 18 }; 17 19 use bevy_ratatui::{RatatuiContext, event::KeyMessage}; 18 20 use ratatui::{ 19 21 layout::{Constraint, HorizontalAlignment, Layout}, 20 - widgets::{Block, Padding, Paragraph}, 22 + widgets::{Block, List, ListDirection, ListItem, Padding, Paragraph}, 21 23 }; 22 24 23 25 use crate::{ 24 - device::{Device, DeviceSocket, SearchingDevices}, 26 + device::{Device, DevicePlugin, DeviceSocket, SearchingDevices}, 27 + net::{MdnsSignaler, NetPlugin}, 25 28 state::AppState, 26 29 }; 27 30 ··· 32 35 fn build(&self, app: &mut bevy::app::App) { 33 36 app.init_resource::<SearchingDevices>() 34 37 .init_state::<AppState>() 38 + .add_plugins((NetPlugin, DevicePlugin)) 35 39 .add_systems(PreUpdate, keybinds) 36 - .add_systems(Update, home_view.run_if(in_state(AppState::Home))); 40 + .add_systems(Update, search_timer) 41 + .add_systems(PostUpdate, home_view.run_if(in_state(AppState::Home))); 37 42 } 38 43 } 39 44 40 45 fn keybinds( 46 + signal: Res<MdnsSignaler>, 41 47 mut key_reader: MessageReader<KeyMessage>, 42 48 mut is_searching: Option<ResMut<SearchingDevices>>, 43 49 mut app_exit: MessageWriter<AppExit>, ··· 47 53 match message.code { 48 54 KeyCode::Char('s') => { 49 55 if let Some(is_searching) = is_searching.as_deref_mut() { 50 - is_searching.0 = !is_searching.0; 56 + if let Some(_) = is_searching.searching { 57 + is_searching.searching = None; 58 + } else { 59 + is_searching.searching = 60 + Some(Timer::from_seconds(1.0, bevy::time::TimerMode::Once)); 61 + } 62 + let _ = signal.0.try_send(()); 51 63 } 52 64 } 53 65 KeyCode::Char('q') | KeyCode::Esc => { ··· 58 70 } 59 71 } 60 72 73 + fn search_timer(mut is_searching: Option<ResMut<SearchingDevices>>, time: Res<Time<Real>>) { 74 + if let Some(s) = is_searching.as_deref_mut() 75 + && let Some(timer) = &mut s.searching 76 + { 77 + timer.tick(time.delta()); 78 + if timer.is_finished() { 79 + s.searching = None; 80 + } 81 + } 82 + } 83 + 61 84 fn home_view( 62 85 mut context: ResMut<RatatuiContext>, 63 86 is_searching: Res<SearchingDevices>, 64 - _q_devices: Query<(&Name, &DeviceSocket), With<Device>>, 87 + q_devices: Query<(&Name, &DeviceSocket), With<Device>>, 65 88 ) -> Result { 66 89 context.draw(|frame| { 67 90 let [top, bottom] = 68 91 Layout::vertical([Constraint::Length(3), Constraint::Fill(1)]).areas(frame.area()); 69 92 70 - let searching = if is_searching.0 { 93 + let searching = if is_searching.searching.is_some() { 71 94 "Searching..." 72 95 } else { 73 96 "Select a Device" ··· 78 101 .title("Striker") 79 102 .title_alignment(HorizontalAlignment::Center), 80 103 ); 104 + 105 + let items = q_devices 106 + .iter() 107 + .map(|(name, addr)| ListItem::new(format!("{}, {}:{}", name, addr.address, addr.port))); 108 + 109 + let list = List::new(items) 110 + .direction(ListDirection::TopToBottom) 111 + .block(Block::bordered().title("Devices")); 112 + 81 113 frame.render_widget(paragraph, top); 82 - frame.render_widget(Block::bordered().title("Devices"), bottom); 114 + frame.render_widget(list, bottom); 83 115 })?; 84 116 85 117 Ok(())
+116
src/net.rs
··· 1 + use std::{ 2 + net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}, 3 + time::Duration, 4 + }; 5 + 6 + use async_channel::{Receiver, Sender}; 7 + use async_io::{Async, Timer}; 8 + use bevy::{ 9 + app::{Plugin, Startup}, 10 + ecs::{resource::Resource, system::Commands}, 11 + tasks::IoTaskPool, 12 + }; 13 + use futures_concurrency::future::Race; 14 + use sachy_mdns::{ 15 + GROUP_SOCK_V4, MDNS_PORT, 16 + client::query_service, 17 + dns::{records::Record, reqres::Response, traits::DnsParse}, 18 + }; 19 + use socket2::{Domain, Protocol, Socket, Type}; 20 + 21 + #[derive(Debug, Resource)] 22 + pub struct DiscoverResponse(pub Receiver<InstanceDetails>); 23 + 24 + pub struct InstanceDetails { 25 + pub host: String, 26 + pub address: String, 27 + pub port: u16, 28 + } 29 + 30 + #[derive(Debug, Resource)] 31 + pub struct MdnsSignaler(pub Sender<()>); 32 + 33 + fn create_mdns_socket() -> std::io::Result<Async<UdpSocket>> { 34 + let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?; 35 + sock.set_reuse_address(true)?; 36 + sock.set_nonblocking(true)?; 37 + sock.bind(&SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())?; 38 + let udp_socket = UdpSocket::from(sock); 39 + Async::new_nonblocking(udp_socket) 40 + } 41 + 42 + pub fn setup_mdns_task(mut commands: Commands) { 43 + let io = IoTaskPool::get(); 44 + 45 + let (signal_tx, signal_rx) = async_channel::bounded(1); 46 + let (resp_tx, resp_rx) = async_channel::bounded(64); 47 + 48 + io.spawn(async move { 49 + let mut buf = vec![0u8; 4096]; 50 + 51 + let udp_socket = create_mdns_socket().unwrap(); 52 + 53 + loop { 54 + if signal_rx.recv().await.is_ok() { 55 + let query_fut = async { 56 + let query = query_service("_picostrike._tcp.local", &mut buf).unwrap(); 57 + 58 + udp_socket.send_to(query, GROUP_SOCK_V4).await.ok(); 59 + 60 + while let Ok((read, _)) = udp_socket.recv_from(&mut buf).await { 61 + let input = &buf[..read]; 62 + let resp = Response::parse(&mut &*input, input).unwrap(); 63 + 64 + if resp 65 + .answers 66 + .iter() 67 + .find(|answer| { 68 + if let Record::PTR(_) = &answer.record { 69 + answer.name == "_picostrike._tcp.local" 70 + } else { 71 + false 72 + } 73 + }) 74 + .is_some() 75 + && let Some(instance) = resp.additional.iter().find_map(|answer| { 76 + if let Record::SRV(srv) = &answer.record { 77 + Some(InstanceDetails { 78 + host: answer.name.to_string(), 79 + address: srv.target.to_string(), 80 + port: srv.port, 81 + }) 82 + } else { 83 + None 84 + } 85 + }) 86 + { 87 + resp_tx.send(instance).await.ok(); 88 + } 89 + } 90 + }; 91 + 92 + let timer = async { 93 + Timer::after(Duration::from_millis(1000)).await; 94 + }; 95 + 96 + let cancel = async { 97 + signal_rx.recv().await.ok(); 98 + }; 99 + 100 + (query_fut, timer, cancel).race().await; 101 + } 102 + } 103 + }) 104 + .detach(); 105 + 106 + commands.insert_resource(DiscoverResponse(resp_rx)); 107 + commands.insert_resource(MdnsSignaler(signal_tx)); 108 + } 109 + 110 + pub struct NetPlugin; 111 + 112 + impl Plugin for NetPlugin { 113 + fn build(&self, app: &mut bevy::app::App) { 114 + app.add_systems(Startup, setup_mdns_task); 115 + } 116 + }
+1 -5
striker-proto/src/lib.rs
··· 16 16 17 17 #[derive(Debug, serde::Serialize, serde::Deserialize)] 18 18 pub enum StrikerResponse { 19 - Response { 20 - response: Response, 21 - }, 19 + Response { response: Response }, 22 20 Update(Update), 23 21 } 24 22 ··· 40 38 average: u16, 41 39 }, 42 40 } 43 - 44 -