forked from sigil-03/number-station
add basic generator + receiver
This commit is contained in:
commit
f2248200dd
4 changed files with 1920 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
1705
Cargo.lock
generated
Normal file
1705
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "number-station"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# Random Number generator
|
||||
rand_core = { version = "0.6.4", features = ["getrandom"] }
|
||||
|
||||
# Async IO
|
||||
tokio = { version = "1.44.2", features = ["full"] }
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-util = "0.7.15"
|
||||
|
||||
# Logging
|
||||
log = "0.4.27"
|
||||
env_logger = "0.10"
|
||||
reticulum = "0.1.0"
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
bincode = { version = "2.0.1", features = ["serde"] }
|
||||
193
src/main.rs
Normal file
193
src/main.rs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rand_core::OsRng;
|
||||
use reticulum::destination::{DestinationName, SingleInputDestination};
|
||||
use reticulum::hash::AddressHash;
|
||||
use reticulum::identity::PrivateIdentity;
|
||||
use reticulum::iface::tcp_client::TcpClient;
|
||||
use reticulum::transport::{Transport, TransportConfig};
|
||||
use reticulum::destination::link::{Link, LinkEvent, LinkStatus};
|
||||
|
||||
|
||||
use tokio::time::interval;
|
||||
|
||||
use crate::number_station::NumberStationPacket;
|
||||
|
||||
mod number_station {
|
||||
use reticulum::hash::AddressHash;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use bincode::{Encode, Decode, BorrowDecode};
|
||||
|
||||
pub struct NumberStation {
|
||||
id: AddressHash,
|
||||
current_number: usize,
|
||||
}
|
||||
|
||||
impl NumberStation {
|
||||
pub fn new(id: AddressHash) -> Self {
|
||||
Self {
|
||||
id,
|
||||
current_number: 0,
|
||||
}
|
||||
}
|
||||
// generate / return the next number in the station
|
||||
pub fn next(&mut self) -> NumberStationPacket {
|
||||
self.current_number = self.current_number.wrapping_add(1);
|
||||
NumberStationPacket {
|
||||
// id: self.id,
|
||||
number: self.current_number,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, BorrowDecode, Debug)]
|
||||
pub struct NumberStationPacket {
|
||||
// id: AddressHash,
|
||||
number: usize,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Mode {
|
||||
Receiver,
|
||||
Generator,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
async fn run_client() {
|
||||
log::info!(">>> NUMBER STATION CLIENT <<<");
|
||||
let mut transport = Transport::new(TransportConfig::default());
|
||||
|
||||
|
||||
|
||||
let client_addr = transport
|
||||
.iface_manager()
|
||||
.lock()
|
||||
.await
|
||||
.spawn(TcpClient::new("127.0.0.1:4242"), TcpClient::spawn);
|
||||
|
||||
log::info!("client ID: {}", client_addr);
|
||||
|
||||
// let id = PrivateIdentity::new_from_rand(OsRng);
|
||||
let id = PrivateIdentity::new_from_name("test-name");
|
||||
log::info!("private ID: {}", id.address_hash());
|
||||
|
||||
// let destination = SingleInputDestination::new(id, DestinationName::new("generator", "number_station.generator"));
|
||||
let destination = transport.add_destination(id, DestinationName::new("receiver", "generator.numbers")).await;
|
||||
log::info!("dest ID: {}", destination.lock().await.desc.address_hash);
|
||||
|
||||
let mut announce_recv = transport.recv_announces().await;
|
||||
let mut out_link_events = transport.out_link_events();
|
||||
|
||||
let mut links = HashMap::<AddressHash, Arc<tokio::sync::Mutex<Link>>>::new();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Ok(announce) = announce_recv.recv() => {
|
||||
let destination = announce.destination.lock().await;
|
||||
log::info!("ANNOUNCE: {}", destination.desc.address_hash);
|
||||
if links.get(&destination.desc.address_hash).is_none() {
|
||||
let link = transport.link(destination.desc).await;
|
||||
links.insert(destination.desc.address_hash, link.clone());
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
Ok(link_event) = out_link_events.recv() => {
|
||||
match link_event.event {
|
||||
LinkEvent::Activated => log::info!("link {} activated", link_event.id),
|
||||
LinkEvent::Closed => log::info!("link {} closed", link_event.id),
|
||||
LinkEvent::Data(payload) => {
|
||||
let payload: NumberStationPacket = bincode::borrow_decode_from_slice(payload.as_slice(), bincode::config::standard()).unwrap().0;
|
||||
log::info!("link {} data payload: {:?}", link_event.id, payload);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_server() {
|
||||
log::info!(">>> NUMBER STATION SERVER <<<");
|
||||
let mut transport = Transport::new(TransportConfig::default());
|
||||
|
||||
|
||||
|
||||
let client_addr = transport
|
||||
.iface_manager()
|
||||
.lock()
|
||||
.await
|
||||
.spawn(TcpClient::new("127.0.0.1:4242"), TcpClient::spawn);
|
||||
|
||||
log::info!("client ID: {}", client_addr);
|
||||
|
||||
let id = PrivateIdentity::new_from_rand(OsRng);
|
||||
// let id = PrivateIdentity::new_from_name("test-name");
|
||||
log::info!("private ID: {}", id.address_hash());
|
||||
|
||||
// let destination = SingleInputDestination::new(id, DestinationName::new("generator", "number_station.generator"));
|
||||
let destination = transport.add_destination(id, DestinationName::new("generator", "generator.numbers")).await;
|
||||
log::info!("dest ID: {}", destination.lock().await.desc.address_hash);
|
||||
|
||||
// let mut announce_recv = transport.recv_announces().await;
|
||||
// let mut out_link_events = transport.out_link_events();
|
||||
let mut in_link_events = transport.in_link_events();
|
||||
|
||||
let mut links = HashMap::<AddressHash, Arc<tokio::sync::Mutex<Link>>>::new();
|
||||
|
||||
let mut number_generator = number_station::NumberStation::new(destination.lock().await.desc.address_hash);
|
||||
|
||||
// let timer_fut = tokio::time::sleep(Duration::from_secs(1));
|
||||
let mut announce_interval = interval(Duration::from_secs(5));
|
||||
let mut number_transmit_interval = interval(Duration::from_secs(1));
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = announce_interval.tick() => {
|
||||
log::info!("announce tick");
|
||||
transport
|
||||
.send_announce(&destination, None)
|
||||
.await;
|
||||
}
|
||||
Ok(link_event) = in_link_events.recv() => {
|
||||
match link_event.event {
|
||||
LinkEvent::Activated => log::info!("inlink {} activated", link_event.id),
|
||||
LinkEvent::Closed => log::info!("inlink {} closed", link_event.id),
|
||||
LinkEvent::Data(payload) => log::info!("inlink {} data payload: {}", link_event.id,
|
||||
std::str::from_utf8(payload.as_slice())
|
||||
.map(str::to_string)
|
||||
.unwrap_or_else(|_| format!("{:?}", payload.as_slice()))),
|
||||
}
|
||||
|
||||
}
|
||||
_ = number_transmit_interval.tick() => {
|
||||
let payload = number_generator.next();
|
||||
log::info!("transmit payload: {:?}", payload);
|
||||
transport.send_to_in_links(&destination.lock().await.desc.address_hash, &bincode::encode_to_vec(payload, bincode::config::standard()).unwrap()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
match cli.mode {
|
||||
Mode::Receiver => run_client().await,
|
||||
Mode::Generator => run_server().await,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue