#![warn(missing_docs)]
use nargo_types::Result;
use std::{
collections::HashMap,
path::{Path, PathBuf},
sync::Arc,
};
use nargo_types::NargoContext;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServerMode {
Dev,
Serve,
Prod,
}
#[derive(Debug, Clone)]
pub struct ServerOptions {
pub mode: ServerMode,
pub root: PathBuf,
pub port: u16,
pub host: String,
}
impl Default for ServerOptions {
fn default() -> Self {
Self { mode: ServerMode::Dev, root: PathBuf::from("."), port: 3000, host: "127.0.0.1".to_string() }
}
}
pub struct DevServer {
options: ServerOptions,
}
impl DevServer {
pub fn new(options: ServerOptions) -> Self {
Self { options }
}
pub async fn start(&self) -> Result<()> {
println!("Dev server running on {}:{}...", self.options.host, self.options.port);
Ok(())
}
}
pub async fn run(_ctx: Arc<NargoContext>, options: ServerOptions) -> Result<()> {
let server = DevServer::new(options);
server.start().await
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MockRoute {
pub path: String,
#[serde(default = "default_method")]
pub method: String,
#[serde(default = "default_status")]
pub status: u16,
#[serde(default)]
pub headers: HashMap<String, String>,
#[serde(default)]
pub body: String,
#[serde(default)]
pub body_file: Option<PathBuf>,
#[serde(default)]
pub delay_ms: u64,
}
fn default_method() -> String {
"GET".to_string()
}
fn default_status() -> u16 {
200
}
pub struct MockServer {
_ctx: Arc<NargoContext>,
routes: Vec<MockRoute>,
}
impl MockServer {
pub fn new(ctx: Arc<NargoContext>) -> Self {
Self { _ctx: ctx, routes: Vec::new() }
}
pub fn add_route(&mut self, route: MockRoute) {
self.routes.push(route);
}
pub fn load_from_dir(&mut self, dir: &Path) -> Result<()> {
for entry in std::fs::read_dir(dir).map_err(|e| nargo_types::Error::external_error("server".to_string(), e.to_string(), nargo_types::Span::unknown()))? {
let entry = entry.map_err(|e| nargo_types::Error::external_error("server".to_string(), e.to_string(), nargo_types::Span::unknown()))?;
let path = entry.path();
if path.extension().map_or(false, |ext| ext == "json") {
let content = std::fs::read_to_string(&path).map_err(|e| nargo_types::Error::external_error("server".to_string(), e.to_string(), nargo_types::Span::unknown()))?;
let routes: Vec<MockRoute> = serde_json::from_str(&content).map_err(|e| nargo_types::Error::external_error("server".to_string(), e.to_string(), nargo_types::Span::unknown()))?;
self.routes.extend(routes);
}
}
Ok(())
}
pub fn routes_count(&self) -> usize {
self.routes.len()
}
pub async fn start(&self, port: u16) -> Result<()> {
println!("Mock server running on port {}...", port);
println!("Loaded {} routes", self.routes.len());
Ok(())
}
}