Initial code commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
25
Cargo.lock
generated
Normal file
25
Cargo.lock
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sus"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "sus"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
getopts = "0.2.21"
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 IIM
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
111
src/main.rs
Normal file
111
src/main.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use std::{env, fs::File, path::{PathBuf}, net::{UdpSocket, IpAddr, Ipv4Addr, SocketAddr}, io::{Seek, Read, ErrorKind}, thread, time::Duration};
|
||||
|
||||
use getopts::Options;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let mut options = Options::new();
|
||||
options.optopt("i", "file", "Video file to parse", "FILE");
|
||||
options.optopt(
|
||||
"s",
|
||||
"chunkspersecond",
|
||||
"Rate at which the chunk bursts will be sent",
|
||||
"NUMBER",
|
||||
);
|
||||
options.optopt(
|
||||
"c",
|
||||
"chunksize",
|
||||
"How large a file chunk should be processed each frame",
|
||||
"NUMBER",
|
||||
);
|
||||
options.optopt(
|
||||
"f",
|
||||
"frame",
|
||||
"Split each chunk into this many frames",
|
||||
"NUMBER",
|
||||
);
|
||||
options.optflag("r", "repeat", "Continue from start of the file after reaching the end");
|
||||
options.optopt("t", "target", "Target address for sending", "IP:PORT");
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let program = args[0].clone();
|
||||
|
||||
let matches = match options.parse(args) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
println!("Error parsing options: {e}");
|
||||
print_usage(program, options);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
if !matches.opt_present("t") || !matches.opt_present("i") {
|
||||
print_usage(program, options);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path = PathBuf::from(matches.opt_str("i").unwrap());
|
||||
let mut file = File::open(path)?;
|
||||
|
||||
|
||||
let chunks_per_second: u32 = matches.opt_get("s").unwrap_or_default().unwrap_or(24);
|
||||
let chunk_size: usize = matches.opt_get("c").unwrap_or_default().unwrap_or(530 * 10);
|
||||
let frame_count: usize = matches.opt_get("f").unwrap_or_default().unwrap_or(10);
|
||||
let frame_size: usize = chunk_size / frame_count;
|
||||
let chunk_interval: f64 = 1.0 / chunks_per_second as f64;
|
||||
let mut repeat = matches.opt_present("f");
|
||||
|
||||
let mut buffer: Vec<u8> = Vec::new();
|
||||
buffer.resize(chunk_size, 0);
|
||||
|
||||
let socket = UdpSocket::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)).unwrap();
|
||||
let target = matches.opt_str("t").unwrap();
|
||||
|
||||
let mut count = 0;
|
||||
let mut frameid = 0;
|
||||
|
||||
while repeat {
|
||||
file.rewind()?;
|
||||
println!("Sending {chunk_size}b large chunks in {frame_size}b parts at rate {chunks_per_second}. Repeat {count}.");
|
||||
loop {
|
||||
frameid += 1;
|
||||
// println!("Sending chunk {frameid} (repeat {count}) per {frame_size} b parts.");
|
||||
match file.read_exact(buffer.as_mut_slice()) {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::UnexpectedEof {
|
||||
println!("Reached end of file.");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
println!("File read error: {e}");
|
||||
repeat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
for fr in 0..frame_count {
|
||||
let frame = &buffer[fr * frame_size .. (fr + 1) * frame_size];
|
||||
|
||||
// for i in 0..frame_size {
|
||||
// print!("{:02X} ", frame[i]);
|
||||
// if i % 24 == 0 {
|
||||
// print!("\n");
|
||||
// }
|
||||
// }
|
||||
// print!("\n");
|
||||
|
||||
socket.send_to(frame, target.clone()).unwrap();
|
||||
}
|
||||
// println!("Sleeping for {chunk_interval}");
|
||||
thread::sleep(Duration::from_secs_f64(chunk_interval));
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_usage(program: String, options: Options) {
|
||||
let brief = format!("Usage: {} -i FILE -t IP:PORT [options]\n\tSimple UDP Sender - takes file contents as sepcified by the arguments and sends them as UDP packets.", program);
|
||||
print!("{}", options.usage(&brief));
|
||||
}
|
||||
Reference in New Issue
Block a user