Skip to content

Commit

Permalink
docs: internal_api & main
Browse files Browse the repository at this point in the history
Signed-off-by: Alexis-Bernard <[email protected]>
  • Loading branch information
alexis-ascoz authored and GridexX committed Apr 9, 2023
1 parent 8609280 commit 658d128
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 30 deletions.
62 changes: 32 additions & 30 deletions agent/lib/src/external_api/service.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
use anyhow::{anyhow, Result};
use log::{error, info, debug, trace};
use log::{debug, error, info, trace};

use serialport::SerialPort;

use super::model::{RequestMessage, ResponseMessage, StatusMessage};
use super::comms::{Message, MESSAGE_SIZE_NB_BYTES};
use super::model::{RequestMessage, ResponseMessage, StatusMessage};

pub struct ExternalApi {
serial_path: String,
serial_baud_rate: u32,

serial_port: Box<dyn SerialPort>, // So we don't open it multiple times
}

impl ExternalApi {
pub fn new(serial_path: String, serial_baud_rate: u32) -> Self {
Self {
serial_path,
serial_path: serial_path.clone(),
serial_baud_rate,
serial_port: serialport::new(serial_path, serial_baud_rate)
.open()
.unwrap(),
}
}

pub fn read_from_serial(&mut self) -> Result<RequestMessage> {
info!("Reading from serial port: {}", self.serial_path);

// Open the serial port
let mut serial = serialport::new(&self.serial_path, self.serial_baud_rate)
.open()
.map_err(|e| anyhow!("Failed to open serial port: {}", e))?;

// Create a buffer to hold the data
let mut data_size: usize = 0;
let mut size_buffer: [u8; MESSAGE_SIZE_NB_BYTES] = [0; MESSAGE_SIZE_NB_BYTES];
Expand All @@ -36,9 +38,9 @@ impl ExternalApi {
// Create the final vector to hold the data
let mut data_received: Vec<u8> = Vec::new();

//we read the buffer and retrieve the first 8 bytes which are the size of the message
//we read the buffer and retrieve the first 8 bytes which are the size of the message
while !got_size {
match serial.read(&mut size_buffer) {
match self.serial_port.read(&mut size_buffer) {
Ok(t) => {
if t == 0 {
break;
Expand All @@ -52,18 +54,15 @@ impl ExternalApi {

if bytes_read >= MESSAGE_SIZE_NB_BYTES {
got_size = true;

let size_string = String::from_utf8(
data_received.clone()
).map_err(
|e| anyhow!("Failed to get message size as string: {}", e)
)?;


let size_string = String::from_utf8(data_received.clone())
.map_err(|e| anyhow!("Failed to get message size as string: {}", e))?;

trace!("Size string: {}", size_string);
data_size = size_string.parse::<usize>().map_err(
|e| anyhow!("Failed to parse length of message: {}", e)
)?;

data_size = size_string
.parse::<usize>()
.map_err(|e| anyhow!("Failed to parse length of message: {}", e))?;

data_received.drain(..MESSAGE_SIZE_NB_BYTES);
}
Expand All @@ -76,7 +75,7 @@ impl ExternalApi {
bytes_read = 0;

while bytes_read < data_size {
match serial.read(&mut buf) {
match self.serial_port.read(&mut buf) {
Ok(t) => {
if t > 0 {
bytes_read += t;
Expand All @@ -97,7 +96,7 @@ impl ExternalApi {
info!("Code entry: {:?}", code_entry);

// Flush the serial port
serial
self.serial_port
.flush()
.map_err(|e| anyhow!("Failed to flush serial port: {}", e))?;

Expand Down Expand Up @@ -137,22 +136,25 @@ impl ExternalApi {
}

pub fn write_to_serial(&mut self, data: &str) -> Result<()> {
// Open the serial port
let mut serial = serialport::new(&self.serial_path, self.serial_baud_rate)
.open()
.map_err(|e| anyhow!("Failed to open serial port: {}", e))?;
info!("Writing to serial port: {}", self.serial_path);

// Conver the string to a byte array
// Convert the string to a byte array
let message = Message::new(data.to_string()).to_bytes();
let buf = message.as_slice();

// Write the byte array to the serial port
serial
self.serial_port
.write_all(buf)
.map_err(|e| anyhow!("Failed to write to serial port: {}", e))?;

// In order to still be readable by ``readline`` on the other side, we add a carriage return
// (not included in the message size)
self.serial_port
.write("\r\n".as_bytes())
.map_err(|e| anyhow!("Failed to write to serial port: {}", e))?;

// Flush the serial port
serial
self.serial_port
.flush()
.map_err(|e| anyhow!("Failed to flush serial port: {}", e))?;
Ok(())
Expand Down
14 changes: 14 additions & 0 deletions agent/lib/src/internal_api/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ use std::path::PathBuf;

use serde::{Deserialize, Serialize};

/// A struct to represent a file in the request message
///
/// # Attributes
///
/// * `path` - The path of the file
/// * `file_name` - The name of the file
/// * `content` - The content of the file
#[derive(Deserialize, Serialize, Debug)]
pub struct FileModel {
pub path: PathBuf,
Expand All @@ -19,6 +26,13 @@ impl FileModel {
}
}

/// A struct to represent the result of a command
///
/// # Attributes
///
/// * `stdout` - The stdout of the command
/// * `stderr` - The stderr of the command
/// * `exit_code` - The exit code of the command
#[derive(Deserialize, Serialize, Debug)]
pub struct CodeReturn {
pub stdout: String,
Expand Down
50 changes: 50 additions & 0 deletions agent/lib/src/internal_api/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,33 @@ use std::{
process::Command,
};

/// The path where the workspace will be created
const WORKSPACE_PATH: &str = "/tmp";

/// The internal API
pub struct InternalApi {
pub request_message: RequestMessage,
}

impl InternalApi {
/// Create a new instance of InternalApi
///
/// # Arguments
///
/// * `request_message` - The request message
///
/// # Returns
///
/// * `Self` - The new instance of InternalApi
pub fn new(request_message: RequestMessage) -> Self {
Self { request_message }
}

/// Create the workspace for the code execution
///
/// # Returns
///
/// * `Result<()>` - Nothing or an error
pub fn create_workspace(&mut self) -> Result<()> {
info!("Creating workspace for code execution");

Expand Down Expand Up @@ -101,6 +117,11 @@ impl InternalApi {
Ok(())
}

/// Run all the steps of the request message
///
/// # Returns
///
/// * `Result<ResponseMessage>` - The response message or an error
pub fn run(&mut self) -> Result<ResponseMessage> {
info!("Running all steps");
let mut steps: Vec<ResponseStep> = Vec::new();
Expand Down Expand Up @@ -135,6 +156,15 @@ impl InternalApi {
Ok(response_message)
}

/// Run a command
///
/// # Arguments
///
/// * `command` - The command to run
///
/// # Returns
///
/// * `Result<CodeReturn>` - The code return or an error
pub fn run_one(&mut self, command: &str) -> Result<CodeReturn> {
info!("Running command : {}", command);

Expand Down Expand Up @@ -167,6 +197,15 @@ mod tests {
use std::fs::File;
use std::io::Read;

/// Generate a random integer
///
/// # Arguments
///
/// * `max` - The maximum value
///
/// # Returns
///
/// * `usize` - The random integer
fn random_usize(max: usize) -> usize {
let mut f = File::open("/dev/urandom").unwrap();
let mut buf = [0u8; 1];
Expand All @@ -180,6 +219,15 @@ mod tests {
}
}

/// Generate a random string
///
/// # Arguments
///
/// * `len` - The length of the string
///
/// # Returns
///
/// * `String` - The random string
fn native_rand_string(len: usize) -> String {
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
let mut string = String::new();
Expand All @@ -191,6 +239,7 @@ mod tests {
string
}

/// Test the creation of a file
#[test]
fn workload_runs_correctly() {
let files: Vec<FileModel> = Vec::new();
Expand Down Expand Up @@ -218,6 +267,7 @@ mod tests {
assert!(res.data.steps[0].enable_output);
}

/// Test the execution of a command with a workspace
#[test]
fn workspace_created_sucessfully() {
let mut base_dir = PathBuf::from(WORKSPACE_PATH);
Expand Down
18 changes: 18 additions & 0 deletions agent/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use anyhow::{anyhow, Result};
use clap::Parser;
use log::{debug, info, trace};

/// Agent CLI options
#[derive(Parser)]
#[clap(
version = "0.1",
Expand All @@ -17,28 +18,45 @@ pub struct AgentOpts {
config: String,
}

/// Main function
fn main() -> Result<()> {
// Initialize logger
env_logger::init();

info!("Starting agent");

// Parse CLI options
let options = AgentOpts::parse();

debug!("loading config file at {}", options.config);

// Load config file
let config = AgentConfig::load(options.config.as_str())?;

trace!(
"config file loaded successfully with content: {:#?}",
config
);

// Initialize external API
let mut external_api = ExternalApi::new(config.serial.path, config.serial.baud_rate);

// Send status message to serial port
external_api.send_status_message()?;

// Read request message from serial port
let request_message = external_api.read_from_serial()?;

// Initialize internal API
let mut internal_api = InternalApi::new(request_message);

// Create the workspace
internal_api.create_workspace()?;

// Run the steps of the request message
let response_message = internal_api.run().map_err(|e| anyhow!("{:?}", e))?;

// Send response message to serial port
external_api.send_response_message(response_message)?;

info!("Stopping agent");
Expand Down

0 comments on commit 658d128

Please sign in to comment.