Skip to content

Commit

Permalink
Merge pull request #54 from jabibamman/develop
Browse files Browse the repository at this point in the history
Feat - server minimal and tests
  • Loading branch information
jabibamman authored Nov 24, 2023
2 parents d55956d + 9e19a82 commit cc987df
Show file tree
Hide file tree
Showing 19 changed files with 430 additions and 46 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ To build all packages in release mode:
cargo build --release
```

To build a specific package in release mode:

```bash
cargo build -p <package_name> --release
```

### Running Specific Packages

To run a specific package, use `-p` followed by the package name. For example, to run the client package:
Expand All @@ -62,6 +68,7 @@ To build the server library (used by other components):

```bash
cargo build -p server
cargo run -p server
```

### Shared
Expand Down Expand Up @@ -90,6 +97,14 @@ You can read the CLI rustdoc documentation for more information on the CLI argum
cargo run -p client -- -h
```

## Running the server with CLI

To run the server with CLI, use the following command:

```bash
cargo run -p server -- -h
```

## Documentation

To generate documentation for all packages without including dependencies (recommended):
Expand Down
1 change: 1 addition & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod operation;
pub mod parser;
69 changes: 69 additions & 0 deletions cli/src/operation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::parser::CliArgs;

/// Parses `CliArgs` to create a formatted address string.
///
/// This function takes an instance of `CliArgs` and returns a string representing an address.
/// It supports both client and server arguments. The address format is "hostname:port".
///
/// ## Parameters
/// - `cli_args`: An instance of `CliArgs`, which can be either `CliClientArgs` or `CliServerArgs`.
///
/// ## Returns
/// A `String` that represents the address in the format "hostname:port".
///
/// ## Examples
/// Assuming `CliArgs::Client` variant is used with hostname "192.168.1.0" and port 8787:
/// ```rust
/// use cli::{parser::{CliClientArgs, Parser, CliArgs}, operation::parse_to_address};
///
/// let client_args = CliArgs::Client(CliClientArgs {
/// hostname: "192.168.1.0".to_string(),
/// port: 8787,
/// worker_name: "worker".to_string(),
/// });
///
/// let address = parse_to_address(client_args);
/// assert_eq!(address, "192.168.1.0:8787");
/// ```
/// Similarly, you can create an instance of `CliArgs::Server` and pass it to this function.
pub fn parse_to_address(cli_args: CliArgs) -> String {
match cli_args {
CliArgs::Client(args) => format!("{}:{}", args.hostname, args.port),
CliArgs::Server(args) => format!("{}:{}", args.hostname, args.port),
}
}

#[cfg(test)]
mod operation_tests {
use super::*;
use crate::parser::{CliArgs, CliClientArgs, CliServerArgs};

pub fn initialize() -> CliServerArgs {
CliServerArgs {
hostname: "127.0.0.1".to_string(),
port: 8787,
}
}

#[test]
fn test_parse_client_to_address() {
let args = initialize();
let client_args = CliArgs::Client(CliClientArgs {
hostname: args.hostname,
port: args.port,
worker_name: "worker".to_string(),
});

let address = parse_to_address(client_args);
assert_eq!(address, "127.0.0.1:8787");
}

#[test]
fn test_parse_server_to_address() {
let args = initialize();
let server_args = CliArgs::Server(args);

let address = parse_to_address(server_args);
assert_eq!(address, "127.0.0.1:8787");
}
}
62 changes: 57 additions & 5 deletions cli/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,74 @@
pub use clap::Parser;

/// # Command line arguments for the CLI
/// Represents command line arguments for a client in a CLI application.
///
/// > This struct is used to parse the command line arguments
/// This struct is used to parse and store command line arguments specific to the client part of an application.
/// It leverages the `clap` crate for argument parsing.
///
/// ## Example
/// ## Fields
/// - `hostname`: A string specifying the hostname. Defaults to "localhost".
/// - `port`: A 16-bit unsigned integer specifying the port number. Defaults to 8787.
/// - `worker_name`: A string specifying the name of the worker. Defaults to "worker".
///
/// ## Example
/// Command line usage might look like this:
/// ```sh
/// worker -H 192.168.1.0 -P 3000 -N my_group_name
/// worker -H 192.168.1.0 -P 8787 -N my_group_name
/// ```
#[derive(Parser, Debug)]
pub struct CliArgs {
pub struct CliClientArgs {
/// The hostname of the client.
/// Default: "localhost"
#[clap(short = 'H', long = "hostname", default_value = "localhost")]
pub hostname: String,

/// The port number to connect on.
/// Default: 8787
#[clap(short = 'P', long = "port", default_value = "8787")]
pub port: u16,

/// The name of the worker.
/// Default: "worker"
#[clap(short = 'N', long = "name", default_value = "worker")]
pub worker_name: String,
}

/// Represents command line arguments for a server in a CLI application.
///
/// Similar to `CliClientArgs`, this struct is for parsing server-specific command line arguments.
/// It uses the `clap` crate for parsing.
///
/// ## Fields
/// - `hostname`: A string specifying the hostname. Defaults to "localhost".
/// - `port`: A 16-bit unsigned integer specifying the port number. Defaults to 8787.
///
/// ## Example
/// Command line usage for the server might be:
/// ```sh
/// server -H 192.168.1.0 -P 8787
/// ```
#[derive(Parser, Debug)]
pub struct CliServerArgs {
/// The hostname of the server.
/// Default: "localhost"
#[clap(short = 'H', long = "hostname", default_value = "localhost")]
pub hostname: String,

/// The port number the server listens on.
/// Default: 8787
#[clap(short = 'P', long = "port", default_value = "8787")]
pub port: u16,
}

/// An enumeration representing the possible types of command line arguments.
///
/// This enum helps in differentiating between client and server command line arguments.
/// It is a common practice in CLI applications to have different sets of arguments for different modes (client/server).
///
/// ## Variants
/// - `Client(CliClientArgs)`: Command line arguments specific to the client.
/// - `Server(CliServerArgs)`: Command line arguments specific to the server.
pub enum CliArgs {
Client(CliClientArgs),
Server(CliServerArgs),
}
57 changes: 57 additions & 0 deletions client/src/fractal_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,60 @@ fn color(intensity: f32) -> [u8; 3] {
+ brightness.2;
[(255.0 * r) as u8, (255.0 * g) as u8, (255.0 * b) as u8]
}

#[cfg(test)]
mod julia_descriptor_tests {
use complex::complex_operations::ComplexOperations;
use shared::types::complex::Complex;
use shared::types::fractal_descriptor::FractalType::Julia;
use shared::types::fractal_descriptor::JuliaDescriptor;
use shared::types::messages::FragmentTask;
use shared::types::point::Point;
use shared::types::range::Range;
use shared::types::resolution::Resolution;
use shared::types::u8data::U8Data;
use shared::utils::type_of::type_of;

use super::*;

#[test]
fn test_generate_julia_set() {
let fragment_task = FragmentTask {
fractal: shared::types::fractal_descriptor::FractalDescriptor {
fractal_type: Julia(JuliaDescriptor {
c: Complex::new(-0.8, 0.156),
divergence_threshold_square: 0.0,
}),
},
resolution: Resolution { nx: 800, ny: 600 },
range: Range {
min: Point { x: -2.0, y: -1.5 },
max: Point { x: 2.0, y: 1.5 },
},
max_iteration: 100,
id: U8Data {
offset: 0,
count: 0,
},
};

let result = generate_fractal_set(fragment_task);

assert_eq!(result.dimensions(), (800, 600));
}

#[test]
fn test_color() {
let intensity = 0.5;

let result = color(intensity);

let test0 = type_of(result[0]);
let test1 = type_of(result[1]);
let test2 = type_of(result[2]);

assert!(test0.eq("u8"));
assert!(test1.eq("u8"));
assert!(test2.eq("u8"));
}
}
27 changes: 20 additions & 7 deletions client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ mod image;

use std::io;

use crate::image::open_image;
use crate::fractal_generation::generate_fractal_set;
use crate::image::open_image;

use cli::parser::{CliArgs, Parser};
use server::services::{connect::connect, reader::read_message};
use cli::operation::parse_to_address;
use cli::parser::{CliArgs, CliClientArgs, Parser};
use server::services::{connect::connect, reader::get_response, write::write};
use shared::types::filesystem::FileExtension;
use shared::types::fractal_descriptor::FractalType::IteratedSinZ;
use shared::types::fractal_descriptor::{FractalDescriptor, IteratedSinZDescriptor};
Expand All @@ -19,10 +20,22 @@ use shared::types::{complex::Complex, resolution::Resolution};
use shared::utils::filesystem::{get_dir_path_buf, get_extension_str, get_file_path};

fn main() -> io::Result<()> {
let args: CliArgs = CliArgs::parse();
let stream = connect(format!("{}:{}", args.hostname, args.port).as_str())?;
let message = read_message(stream);
println!("{}", message);
let cli_args: CliArgs = CliArgs::Client(CliClientArgs::parse());
let connection_result = connect(&parse_to_address(cli_args));

if let Ok(mut stream) = connection_result {
println!("Connected to the server!");
match write(&mut stream, "Hello World !") {
Ok(_) => println!("Message sent!"),
Err(error) => println!("Failed to send message: {}", error),
}

let response = get_response(&mut stream)?;
println!("Response received: {:?}", response);
} else if let Err(e) = connection_result {
println!("Failed to connect: {}", e);
}

let img_path = match get_dir_path_buf() {
Ok(dir_path_buf) => {
match get_file_path("julia", dir_path_buf, get_extension_str(FileExtension::PNG)) {
Expand Down
1 change: 1 addition & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2021"
[dependencies]
complex = { path = "../complex" }
shared = { path = "../shared" }
cli = { path = "../cli" }

[lib]
path = "src/lib.rs"
42 changes: 42 additions & 0 deletions server/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1 +1,43 @@
use std::{io::Read, net::TcpStream};

/// Handles a client TCP stream.
///
/// This function is responsible for managing a single client TCP stream. It performs the following actions:
/// - Retrieves and prints the local address of the stream.
/// - Reads data from the stream into a buffer and prints the received message.
/// - Handles potential errors in both steps and prints relevant error messages.
///
/// ## Parameters
/// - `stream`: A mutable reference to a `TcpStream`. This stream represents the connection with the client.
///
/// ## Panics
/// This function doesn't explicitly panic, but operations on `stream` (like `read`) might panic if they encounter irrecoverable errors.
///
/// ## Example Usage
/// Note: This example is a conceptual representation and may not work as-is.
/// ```no_run
/// use std::net::{TcpListener, TcpStream};
/// use server::handler::handle_client;
///
/// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
/// for stream in listener.incoming() {
/// if let Ok(stream) = stream {
/// handle_client(stream);
/// }
/// }
/// ```
pub fn handle_client(mut stream: TcpStream) {
match stream.local_addr() {
Ok(addr) => println!("[SERVER] Connection established {}", addr),
Err(e) => println!("[SERVER] Failed to get local address: {}", e),
}

let mut buffer = [0; 1024];
match stream.read(&mut buffer) {
Ok(_) => println!(
"[SERVER] Message received: {}",
String::from_utf8_lossy(&buffer[..])
),
Err(e) => println!("[SERVER] Error reading from stream: {}", e),
}
}
16 changes: 16 additions & 0 deletions server/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use cli::{
operation::parse_to_address,
parser::{CliArgs, CliServerArgs, Parser},
};
use server::services::server_runner::run_server;

fn main() -> std::io::Result<()> {
let cli_args: CliArgs = CliArgs::Server(CliServerArgs::parse());
let address = parse_to_address(cli_args);
match run_server(address.as_str()) {
Ok(_) => println!("[SERVER] Server stopped."),
Err(e) => println!("[SERVER] Server stopped with error: {}", e),
}

Ok(())
}
1 change: 1 addition & 0 deletions server/src/services/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod connect;
pub mod reader;
pub mod server_runner;
pub mod write;
Loading

0 comments on commit cc987df

Please sign in to comment.