8000 GitHub - linrongbin16/dune-event-loop: A multi-platform event loop library 🎡
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

linrongbin16/dune-event-loop

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dune's Event Loop Library

This library is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by Dune, but can be also used in any Rust project.

GitHub GitHub Workflow Status

Features

  • Timers
  • Asynchronous TCP sockets
  • Thread pool
  • File system events
  • Signals

Documentation

Timer handles are used to schedule callbacks to be called in the future.

fn main() {
    let mut event_loop = EventLoop::default();
    let handle = event_loop.handle();

    handle.timer(1000, false, |h: LoopHandle| {
        println!("Hello!");
        h.timer(2500, false, |_: LoopHandle| println!("Hello, world!"));
    });

    while event_loop.has_pending_events() {
        event_loop.tick();
    }
}

This library also provides a thread-pool which can be used to run user code and get notified in the loop thread. This thread pool is internally used by the Dune runtime to run all file system operations, as well as DNS lookups.

fn main() {
    let mut event_loop = EventLoop::default();
    let handle = event_loop.handle();

    let read_file = || {
        let content = std::fs::read_to_string("./examples/async.rs").unwrap();
        Some(Ok(content.as_bytes().to_vec()))
    };

    let read_file_cb = |_: LoopHandle, result: TaskResult| {
        let bytes = result.unwrap().unwrap();
        let content = std::str::from_utf8(&bytes).unwrap();
        println!("{}", content);
    };

    handle.spawn(read_file, Some(read_file_cb));

    while event_loop.has_pending_events() {
        event_loop.tick();
    }
}

TCP handles are used to create TCP socket streams.

fn main() {
    let mut event_loop = EventLoop::default();
    let handle = event_loop.handle();

    let on_close = |_: LoopHandle| println!("Connection closed.");

    let on_write = |_: LoopHandle, _: Index, result: Result<usize>| {
        if let Err(e) = result {
            eprintln!("{}", e);
        }
    };

    let on_read = move |h: LoopHandle, index: Index, data: Result<Vec<u8>>| {
        match data {
            Ok(data) if data.is_empty() => h.tcp_close(index, on_close),
            Ok(data) => h.tcp_write(index, &data, on_write),
            Err(e) => eprintln!("{}", e),
        };
    };

    let on_new_connection =
        move |h: LoopHandle, index: Index, socket: Result<TcpSocketInfo>| match socket {
            Ok(_) => h.tcp_read_start(index, on_read),
            Err(e) => eprintln!("{}", e),
        };

    match handle.tcp_listen("127.0.0.1:9000", on_new_connection) {
        Ok(_) => println!("Server is listening on 127.0.0.1:9000"),
        Err(e) => eprintln!("{}", e),
    };

    while event_loop.has_pending_events() {
        event_loop.tick();
    }
}

You can also connect to a remote host using a TCP handle.

handle
    .tcp_connect("104.21.45.178:80", on_connection)
    .unwrap();

FS handles are used to watch specified paths for changes.

fn main() {
    let mut event_loop = EventLoop::default();
    let handle = event_loop.handle();

    let on_event = |_: LoopHandle, event: FsEvent| {
        println!("{event:?}");
    };

    let directory = "./examples/";
    let rid = match handle.fs_event_start(directory, true, on_event) {
        Ok(rid) => rid,
        Err(e) => {
            println!("{e}");
            return;
        }
    };

    handle.timer(10000, false, move |h: LoopHandle| h.fs_event_stop(&rid));

    while event_loop.has_pending_events() {
        event_loop.tick();
    }
}

Signal handles are wrappers around UNIX signals with some Windows support as well.

Certain signals, such as SIGKILL or SIGSTOP, cannot be overridden or subscribed to. Additionally, on the Windows platform, only SIGINT is supported.

fn main() {
    let mut event_loop = EventLoop::default();
    let handle = event_loop.handle();
    let ctrl_c = Rc::new(Cell::new(false));

    // Exit the program on double CTRL+C.
    let on_signal = move |_: LoopHandle, _: i32| {
        match ctrl_c.get() {
            true => std::process::exit(0),
            false => ctrl_c.set(true),
        };
    };

    handle.signal_start(SIGINT, on_signal).unwrap();

    loop {
        // We need somehow to keep the program running cause signal
        // listeners wont keep the event-loop alive.
        event_loop.tick();
    }
}

To create one-time signal handles, utilize the signal_start_oneshot() function.

handle.signal_start_oneshot(SIGINT, on_signal).unwrap();

For terminating the listener, signal_stop() serves as the appropriate function.

5308
let token = handle.signal_start(SIGINT, on_signal).unwrap();

handle.signal_stop(&token);

You can run all the above examples located in /examples folders using cargo: cargo run --example [name]

About

A multi-platform event loop library 🎡

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Rust 100.0%
0