Skip to content

Commit

Permalink
Merge pull request libp2p#2 from dvc94ch/fallback
Browse files Browse the repository at this point in the history
Fallback
  • Loading branch information
dvc94ch authored Nov 30, 2020
2 parents 1b0aa48 + 94bcf97 commit 76a1e18
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 9 deletions.
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
on: [push, pull_request]

name: if-watch

jobs:
ci:
strategy:
fail-fast: false
matrix:
toolchain:
- rust: stable
#- rust: nightly
platform:
- target: x86_64-unknown-linux-gnu
host: ubuntu-latest
cross: false

- target: x86_64-apple-darwin
host: macos-latest
cross: false

- target: x86_64-pc-windows-msvc
host: windows-latest
cross: false

- target: armv7-linux-androideabi
host: ubuntu-latest
cross: true
- target: aarch64-linux-android
host: ubuntu-latest
cross: true

- target: aarch64-apple-ios
host: macos-latest
cross: true
env:
RUST_BACKTRACE: 1
CARGO_INCREMENTAL: 0
LLVM_CONFIG_PATH: /usr/local/opt/llvm/bin/llvm-config
NDK_HOME: /usr/local/lib/android/sdk/ndk-bundle

runs-on: ${{ matrix.platform.host }}
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Cache cargo folder
uses: actions/cache@v1
with:
path: ~/.cargo
key: ${{ matrix.platform.target }}-cargo-${{ matrix.toolchain.rust }}

- name: Install dependencies ubuntu
if: matrix.platform.host == 'ubuntu-latest'
run: sudo apt-get install llvm-dev

- name: Install dependencies macos
if: matrix.platform.host == 'macos-latest'
run: brew install llvm

- name: Install dependencies windows
if: matrix.platform.host == 'windows-latest'
run: choco install llvm

- name: Install rust toolchain
uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.toolchain.rust }}
targets: ${{ matrix.platform.target }}

- name: Install cargo-ndk
if: contains(matrix.platform.target, 'android')
run: cargo install cargo-ndk

- name: Build
if: contains(matrix.platform.target, 'android') == false
run: cargo build --workspace --all-features --target ${{ matrix.platform.target }}

- name: Build android
if: contains(matrix.platform.target, 'android')
run: cargo ndk --android-platform 29 --target ${{ matrix.platform.target }} build --workspace --all-features

- name: Rust tests
if: matrix.platform.cross == false
run: cargo test --workspace --all-features

lint-rust:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Cache cargo folder
uses: actions/cache@v1
with:
path: ~/.cargo
key: lint-cargo

- name: Install rust toolchain
uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
components: clippy, rustfmt

- name: cargo fmt
run: cargo fmt --all -- --check

- name: cargo clippy
run: cargo clippy --workspace --all-features --examples --tests -- -D warnings
14 changes: 8 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ repository = "https://github.com/dvc94ch/if-watch"
[dependencies]
futures-lite = "1.11.2"
ipnet = "2.3.0"
libc = "0.2.66"
libc = "0.2.80"
log = "0.4.11"

[target.'cfg(unix)'.dependencies]
async-io = "1.2.0"
[target.'cfg(not(windows))'.dependencies]
async-io = "1.3.0"

[target.'cfg(not(target_os = "linux"))'.dependencies]
if-addrs = "0.6.5"

[target.'cfg(windows)'.dependencies]
futures = { version = "0.3.8", default-features = false }
if-addrs = "0.6.5"
winapi = { version = "0.3.8", features = ["netioapi", "ntdef", "winerror", "ws2def"] }
winapi = { version = "0.3.9", features = ["netioapi", "ntdef", "winerror", "ws2def"] }

[dev-dependencies]
env_logger = "0.8.1"
env_logger = "0.8.2"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Got event Ok(Up(fe80::cef9:e4ff:fe9e:b23b/64))
```

Supported platforms at the moment are:
Linux, Windows and Android
Linux, Windows and Android with a fallback for Macos and ios that polls for changes every 10s.

## License
MIT OR Apache-2.0
82 changes: 82 additions & 0 deletions src/fallback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::IfEvent;
use async_io::Timer;
use futures_lite::StreamExt;
use if_addrs::IfAddr;
use ipnet::{IpNet, Ipv4Net, Ipv6Net};
use std::io::Result;
use std::{
collections::{HashSet, VecDeque},
time::{Duration, Instant},
};

/// An address set/watcher
#[derive(Debug)]
pub struct IfWatcher {
addrs: HashSet<IpNet>,
queue: VecDeque<IfEvent>,
ticker: Timer,
}

impl IfWatcher {
/// Create a watcher
pub async fn new() -> Result<Self> {
Ok(Self {
addrs: Default::default(),
queue: Default::default(),
ticker: Timer::interval_at(Instant::now(), Duration::from_secs(10)),
})
}

fn resync(&mut self) -> Result<()> {
let addrs = if_addrs::get_if_addrs()?;
for old_addr in self.addrs.clone() {
if addrs
.iter()
.find(|addr| addr.ip() == old_addr.addr())
.is_none()
{
self.addrs.remove(&old_addr);
self.queue.push_back(IfEvent::Down(old_addr));
}
}
for new_addr in addrs {
let ipnet = ifaddr_to_ipnet(new_addr.addr);
if self.addrs.insert(ipnet) {
self.queue.push_back(IfEvent::Up(ipnet));
}
}
Ok(())
}

pub fn iter(&self) -> impl Iterator<Item = &IpNet> {
self.addrs.iter()
}

/// Returns a future for the next event.
pub async fn next(&mut self) -> Result<IfEvent> {
loop {
if let Some(event) = self.queue.pop_front() {
return Ok(event);
}
self.ticker.next().await;
self.resync()?;
}
}
}

fn ifaddr_to_ipnet(addr: IfAddr) -> IpNet {
match addr {
IfAddr::V4(ip) => {
let prefix_len = (!u32::from_be_bytes(ip.netmask.octets())).leading_zeros();
IpNet::V4(
Ipv4Net::new(ip.ip, prefix_len as u8).expect("if_addrs returned a valid prefix"),
)
}
IfAddr::V6(ip) => {
let prefix_len = (!u128::from_be_bytes(ip.netmask.octets())).leading_zeros();
IpNet::V6(
Ipv6Net::new(ip.ip, prefix_len as u8).expect("if_addrs returned a valid prefix"),
)
}
}
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ use std::io::Result;
#[cfg(not(any(unix, windows)))]
compile_error!("Only Unix and Windows are supported");

#[cfg(unix)]
#[cfg(not(any(target_os = "linux", windows)))]
mod fallback;
#[cfg(target_os = "linux")]
mod unix;
#[cfg(windows)]
mod windows;

#[cfg(unix)]
#[cfg(not(any(target_os = "linux", windows)))]
use fallback as platform_impl;
#[cfg(target_os = "linux")]
use unix as platform_impl;
#[cfg(windows)]
use windows as platform_impl;
Expand Down

0 comments on commit 76a1e18

Please sign in to comment.