flute/lib.rs
1//! [](https://github.com/ypo/flute/actions/workflows/rust.yml)
2//! [](https://github.com/ypo/flute/actions/workflows/python.yml)
3//! [](https://docs.rs/crate/flute/)
4//! [](https://crates.io/crates/flute/)
5//! [](https://deps.rs/repo/github/ypo/flute)
6//! [](https://codecov.io/gh/ypo/flute)
7//!
8//! # FLUTE - File Delivery over Unidirectional Transport
9//!
10//!
11//! Massively scalable multicast distribution solution
12//!
13//! The library implements a unidirectional file delivery, without the need of a return channel.
14//!
15//!
16//! # RFC
17//!
18//! This library implements the following RFCs
19//!
20//!| RFC | Title | Link |
21//!| -------- | ---------- | -----------|
22//!| RFC 6726 | FLUTE - File Delivery over Unidirectional Transport | <https://www.rfc-editor.org/rfc/rfc6726.html> |
23//!| RFC 5775 | Asynchronous Layered Coding (ALC) Protocol Instantiation | <https://www.rfc-editor.org/rfc/rfc5775.html> |
24//!| RFC 5661 | Layered Coding Transport (LCT) Building Block | <https://www.rfc-editor.org/rfc/rfc5651> |
25//!| RFC 5052 | Forward Error Correction (FEC) Building Block | <https://www.rfc-editor.org/rfc/rfc5052> |
26//!| RFC 5510 | Reed-Solomon Forward Error Correction (FEC) Schemes | <https://www.rfc-editor.org/rfc/rfc5510.html> |
27//!| 3GPP TS 26.346 | Extended FLUTE FDT Schema (7.2.10) | <https://www.etsi.org/deliver/etsi_ts/126300_126399/126346/17.03.00_60/ts_126346v170300p.pdf> |
28//!
29//! # Thread Safety
30//!
31//! ## FLUTE Sender
32//!
33//! The FLUTE Sender is designed to be safely shared between multiple threads.
34//!
35//! ## FLUTE Receiver and Tokio Integration
36//!
37//! Unlike the sender, the FLUTE Receiver **is not thread-safe** and cannot be shared between multiple threads.
38//! To integrate it with Tokio, you must use `tokio::task::LocalSet`, which allows spawning tasks that require a single-threaded runtime.
39//!
40//! The following example demonstrates how to use the FLUTE Receiver with Tokio:
41//!
42//!```ignore
43//! use flute::receiver::{writer, MultiReceiver};
44//! use std::rc::Rc;
45//!
46//!#[tokio::main]
47//!async fn main() {
48//! let local = task::LocalSet::new();
49//! // Run the local task set.
50//! local.run_until(async move {
51//! let nonsend_data = nonsend_data.clone();
52//! task::spawn_local(async move {
53//! let writer = Rc::new(writer::ObjectWriterFSBuilder::new(&std::path::Path::new("./flute_dir")).unwrap_or_else(|_| std::process::exit(0)));
54//! let mut receiver = MultiReceiver::new(writer, None, false);
55//! // ... run the receiver
56//! }).await.unwrap();
57//! }).await;
58//!}
59//!```
60//! # UDP/IP Multicast files sender
61//!
62//! Transfer files over a UDP/IP network
63//!
64//!```rust
65//! use flute::sender::Sender;
66//! use flute::sender::ObjectDesc;
67//! use flute::core::lct::Cenc;
68//! use flute::core::UDPEndpoint;
69//! use std::net::UdpSocket;
70//! use std::time::SystemTime;
71//!
72//! // Create UDP Socket
73//! let udp_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
74//! udp_socket.connect("224.0.0.1:3400").expect("Connection failed");
75//!
76//! // Create FLUTE Sender
77//! let tsi = 1;
78//! let oti = Default::default();
79//! let config = Default::default();
80//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
81//! let mut sender = Sender::new(endpoint, tsi, &oti, &config);
82//!
83//! // Add object(s) (files) to the FLUTE sender (priority queue 0)
84//! let obj = ObjectDesc::create_from_buffer(b"hello world".to_vec(), "text/plain",
85//! &url::Url::parse("file:///hello.txt").unwrap(), 1, None, None, None, None, Cenc::Null, true, None, true).unwrap();
86//! sender.add_object(0, obj);
87//!
88//! // Always call publish after adding objects
89//! sender.publish(SystemTime::now());
90//!
91//! // Send FLUTE packets over UDP/IP
92//! while let Some(pkt) = sender.read(SystemTime::now()) {
93//! udp_socket.send(&pkt).unwrap();
94//! std::thread::sleep(std::time::Duration::from_millis(1));
95//! }
96//!
97//!```
98//! # UDP/IP Multicast files receiver
99//!
100//! Receive files from a UDP/IP network
101//!
102//!```
103//! use flute::receiver::{writer, MultiReceiver};
104//! use flute::core::UDPEndpoint;
105//! use std::net::UdpSocket;
106//! use std::time::SystemTime;
107//! use std::rc::Rc;
108//!
109//! // Create UDP/IP socket to receive FLUTE pkt
110//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
111//! let udp_socket = UdpSocket::bind(format!("{}:{}", endpoint.destination_group_address, endpoint.port)).expect("Fail to bind");
112//!
113//! // Create a writer able to write received files to the filesystem
114//! let writer = Rc::new(writer::ObjectWriterFSBuilder::new(&std::path::Path::new("./flute_dir"))
115//! .unwrap_or_else(|_| std::process::exit(0)));
116//!
117//! // Create a multi-receiver capable of de-multiplexing several FLUTE sessions
118//! let mut receiver = MultiReceiver::new(writer, None, false);
119//!
120//! // Receive pkt from UDP/IP socket and push it to the FLUTE receiver
121//! let mut buf = [0; 2048];
122//! loop {
123//! let (n, _src) = udp_socket.recv_from(&mut buf).expect("Failed to receive data");
124//! let now = SystemTime::now();
125//! receiver.push(&endpoint, &buf[..n], now).unwrap();
126//! receiver.cleanup(now);
127//! }
128//!```
129//! # Application-Level Forward Erasure Correction (AL-FEC)
130//!
131//! The following error recovery algorithms are supported
132//!
133//! - [X] No-code
134//! - [X] Reed-Solomon GF 2^8
135//! - [X] Reed-Solomon GF 2^8 Under Specified
136//! - [ ] Reed-Solomon GF 2^16
137//! - [ ] Reed-Solomon GF 2^m
138//! - [X] RaptorQ
139//! - [X] Raptor
140//!
141//! The `Oti` module provides an implementation of the Object Transmission Information (OTI)
142//! used to configure Forward Error Correction (FEC) encoding in the FLUTE protocol.
143//!
144//!```rust
145//! use flute::sender::Sender;
146//! use flute::core::Oti;
147//! use flute::core::UDPEndpoint;
148//!
149//! // Reed Solomon 2^8 with encoding blocks composed of
150//! // 60 source symbols and 4 repair symbols of 1424 bytes per symbol
151//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
152//! let oti = Oti::new_reed_solomon_rs28(1424, 60, 4).unwrap();
153//! let mut sender = Sender::new(endpoint, 1, &oti, &Default::default());
154//!```
155//!
156//! # Content Encoding (CENC)
157//!
158//! The following schemes are supported during the transmission/reception
159//!
160//! - [x] Null (no compression)
161//! - [x] Deflate
162//! - [x] Zlib
163//! - [x] Gzip
164//!
165//! # Files multiplex / Blocks interleave
166//!
167//! The FLUTE Sender is able to transfer multiple files in parallel by interleaving packets from each file. For example:
168//!
169//! **Pkt file1** -> Pkt file2 -> Pkt file3 -> **Pkt file1** -> Pkt file2 -> Pkt file3 ...
170//!
171//! The Sender can interleave blocks within a single file.
172//! The following example shows Encoding Symbols (ES) from different blocks (B) are interleaved. For example:
173//!
174//! **(B 1,ES 1)**->(B 2,ES 1)->(B 3,ES 1)->**(B 1,ES 2)**->(B 2,ES 2)...
175//!
176//! To configure the multiplexing, use the `Config` struct as follows:
177//!
178//!```rust
179//! use flute::sender::Sender;
180//! use flute::sender::Config;
181//! use flute::sender::PriorityQueue;
182//! use flute::core::UDPEndpoint;
183//!
184//! let mut config = Config {
185//! // Interleave a maximum of 3 blocks within each file
186//! interleave_blocks: 3,
187//! ..Default::default()
188//! };
189//!
190//! // Interleave a maximum of 3 files in priority queue '0'
191//! config.set_priority_queue(PriorityQueue::HIGHEST, PriorityQueue::new(3));
192//!
193//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
194//! let mut sender = Sender::new(endpoint, 1, &Default::default(), &config);
195//!```
196//!
197//! # Priority Queues
198//!
199//! FLUTE sender can be configured with multiple queues, each having a different priority level.
200//! Files in higher priority queues are always transferred before files in lower priority queues.
201//! Transfer of files in lower priority queues is paused while there are files to be transferred in higher priority queues.
202//!
203//!```rust
204//!
205//! use flute::sender::Sender;
206//! use flute::sender::Config;
207//! use flute::sender::PriorityQueue;
208//! use flute::core::UDPEndpoint;
209//! use flute::sender::ObjectDesc;
210//! use flute::core::lct::Cenc;
211//!
212//! // Create a default configuration
213//! let mut config: flute::sender::Config = Default::default();
214//!
215//! // Configure the HIGHEST priority queue with a capacity of 3 simultaneous file transfer
216//! config.set_priority_queue(PriorityQueue::HIGHEST, PriorityQueue::new(3));
217//!
218//! // Configure the LOW priority queue with a capacity of 1 file transfer at a time
219//! config.set_priority_queue(PriorityQueue::LOW, PriorityQueue::new(1));
220//!
221//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
222//! let mut sender = Sender::new(endpoint, 1, &Default::default(), &config);
223//!
224//! // Create an ObjectDesc for a low priority file
225//! let low_priority_obj = ObjectDesc::create_from_buffer(b"low priority".to_vec(), "text/plain",
226//! &url::Url::parse("file:///low_priority.txt").unwrap(), 1, None, None, None, None, Cenc::Null, true, None, true).unwrap();
227//!
228//! // Create an ObjectDesc for a high priority file
229//! let high_priority_obj = ObjectDesc::create_from_buffer(b"high priority".to_vec(), "text/plain",
230//! &url::Url::parse("file:///high_priority.txt").unwrap(), 1, None, None, None, None, Cenc::Null, true, None, true).unwrap();
231//!
232//! // Put Object to the low priority queue
233//! sender.add_object(PriorityQueue::LOW, low_priority_obj);
234//!
235//! // Put Object to the high priority queue
236//! sender.add_object(PriorityQueue::HIGHEST, high_priority_obj);
237//!```
238//!
239//! # Bitrate Control
240//!The FLUTE library does not provide a built-in bitrate control mechanism.
241//! Users are responsible for controlling the bitrate by sending packets at a specific rate.
242//! However, the library offers a way to control the target transfer duration or the target transfer end time for each file individually.
243//!
244//!To ensure proper functionality, the target transfer mechanism requires that the overall bitrate is sufficiently high.
245//!
246//! ## Target Transfer Duration
247//!
248//! The sender will attempt to transfer the file within the specified duration.
249//!
250//!```rust
251//!
252//! use flute::sender::Sender;
253//! use flute::sender::ObjectDesc;
254//! use flute::sender::TargetAcquisition;
255//! use flute::core::lct::Cenc;
256//! use flute::core::UDPEndpoint;
257//! use std::net::UdpSocket;
258//! use std::time::SystemTime;
259//!
260//! // Create UDP Socket
261//! let udp_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
262//! udp_socket.connect("224.0.0.1:3400").expect("Connection failed");
263//!
264//! // Create FLUTE Sender
265//! let tsi = 1;
266//! let oti = Default::default();
267//! let config = Default::default();
268//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
269//! let mut sender = Sender::new(endpoint, tsi, &oti, &config);
270//!
271//! // Create an Object
272//! let mut obj = ObjectDesc::create_from_buffer(b"hello world".to_vec(), "text/plain",
273//! &url::Url::parse("file:///hello.txt").unwrap(), 1, None, None, None, None, Cenc::Null, true, None, true).unwrap();
274//!
275//! // Set the Target Transfer Duration of this object to 2 seconds
276//! obj.target_acquisition = Some(TargetAcquisition::WithinDuration(std::time::Duration::from_secs(2)));
277//!
278//! // Add object(s) (files) to the FLUTE sender (priority queue 0)
279//! sender.add_object(0, obj);
280//!
281//! // Always call publish after adding objects
282//! sender.publish(SystemTime::now());
283//!
284//! // Send FLUTE packets over UDP/IP
285//! while sender.nb_objects() > 0 {
286//! if let Some(pkt) = sender.read(SystemTime::now()) {
287//! udp_socket.send(&pkt).unwrap();
288//! } else {
289//! std::thread::sleep(std::time::Duration::from_millis(1));
290//! }
291//! }
292//!```
293//!
294//! ## Target Time to End Transfer
295//!
296//! The sender will try to finish the file at the specified time.
297//!
298//!```rust
299//!
300//! use flute::sender::Sender;
301//! use flute::sender::ObjectDesc;
302//! use flute::sender::TargetAcquisition;
303//! use flute::core::lct::Cenc;
304//! use flute::core::UDPEndpoint;
305//! use std::net::UdpSocket;
306//! use std::time::SystemTime;
307//!
308//! // Create UDP Socket
309//! let udp_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
310//! udp_socket.connect("224.0.0.1:3400").expect("Connection failed");
311//!
312//! // Create FLUTE Sender
313//! let tsi = 1;
314//! let oti = Default::default();
315//! let config = Default::default();
316//! let endpoint = UDPEndpoint::new(None, "224.0.0.1".to_string(), 3400);
317//! let mut sender = Sender::new(endpoint, tsi, &oti, &config);
318//!
319//! // Create an Object
320//! let mut obj = ObjectDesc::create_from_buffer(b"hello world".to_vec(), "text/plain",
321//! &url::Url::parse("file:///hello.txt").unwrap(), 1, None, None, None, None, Cenc::Null, true, None, true).unwrap();
322//!
323//! // Set the Target Transfer End Time of this object to 10 seconds from now
324//! let target_end_time = SystemTime::now() + std::time::Duration::from_secs(10);
325//! obj.target_acquisition = Some(TargetAcquisition::WithinTime(target_end_time));
326//!
327//! // Add object(s) (files) to the FLUTE sender (priority queue 0)
328//! sender.add_object(0, obj);
329//!
330//! // Always call publish after adding objects
331//! sender.publish(SystemTime::now());
332//!
333//! // Send FLUTE packets over UDP/IP
334//! while sender.nb_objects() > 0 {
335//! if let Some(pkt) = sender.read(SystemTime::now()) {
336//! udp_socket.send(&pkt).unwrap();
337//! } else {
338//! std::thread::sleep(std::time::Duration::from_millis(1));
339//! }
340//! }
341//!```
342
343#![deny(missing_docs)]
344#![deny(missing_debug_implementations)]
345#![cfg_attr(test, deny(warnings))]
346
347mod common;
348mod fec;
349mod tools;
350
351pub mod receiver;
352pub mod sender;
353pub use crate::tools::error;
354
355/// Core module with low-level function
356pub mod core {
357
358 /// ALC packets
359 pub mod alc {
360 pub use crate::common::alc::get_sender_current_time;
361 pub use crate::common::alc::parse_alc_pkt;
362 pub use crate::common::alc::parse_payload_id;
363 pub use crate::common::alc::AlcPkt;
364 pub use crate::common::alc::PayloadID;
365 }
366
367 /// LCT packets
368 pub mod lct {
369 pub use crate::common::lct::get_ext;
370 pub use crate::common::lct::inc_hdr_len;
371 pub use crate::common::lct::push_lct_header;
372 pub use crate::common::lct::Cenc;
373 pub use crate::common::lct::LCTHeader;
374 }
375
376 pub use crate::common::oti::FECEncodingID;
377 pub use crate::common::oti::Oti;
378 pub use crate::common::udpendpoint::UDPEndpoint;
379}
380
381#[cfg(feature = "python")]
382mod py;
383
384#[cfg(test)]
385mod tests {
386 pub fn init() {
387 std::env::set_var("RUST_LOG", "debug");
388 env_logger::builder().is_test(true).try_init().ok();
389 }
390}