1#![warn(missing_docs)]
6
7use nargo_types::Result;
8use std::{
9 collections::HashMap,
10 path::{Path, PathBuf},
11 sync::Arc,
12};
13
14use nargo_types::NargoContext;
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum ServerMode {
20 Dev,
22 Serve,
24 Prod,
26}
27
28#[derive(Debug, Clone)]
30pub struct ServerOptions {
31 pub mode: ServerMode,
33 pub root: PathBuf,
35 pub port: u16,
37 pub host: String,
39}
40
41impl Default for ServerOptions {
42 fn default() -> Self {
43 Self { mode: ServerMode::Dev, root: PathBuf::from("."), port: 3000, host: "127.0.0.1".to_string() }
44 }
45}
46
47pub struct DevServer {
49 options: ServerOptions,
50}
51
52impl DevServer {
53 pub fn new(options: ServerOptions) -> Self {
55 Self { options }
56 }
57
58 pub async fn start(&self) -> Result<()> {
60 println!("Dev server running on {}:{}...", self.options.host, self.options.port);
61 Ok(())
62 }
63}
64
65pub async fn run(_ctx: Arc<NargoContext>, options: ServerOptions) -> Result<()> {
67 let server = DevServer::new(options);
68 server.start().await
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct MockRoute {
74 pub path: String,
76 #[serde(default = "default_method")]
78 pub method: String,
79 #[serde(default = "default_status")]
81 pub status: u16,
82 #[serde(default)]
84 pub headers: HashMap<String, String>,
85 #[serde(default)]
87 pub body: String,
88 #[serde(default)]
90 pub body_file: Option<PathBuf>,
91 #[serde(default)]
93 pub delay_ms: u64,
94}
95
96fn default_method() -> String {
97 "GET".to_string()
98}
99
100fn default_status() -> u16 {
101 200
102}
103
104pub struct MockServer {
106 _ctx: Arc<NargoContext>,
107 routes: Vec<MockRoute>,
108}
109
110impl MockServer {
111 pub fn new(ctx: Arc<NargoContext>) -> Self {
113 Self { _ctx: ctx, routes: Vec::new() }
114 }
115
116 pub fn add_route(&mut self, route: MockRoute) {
118 self.routes.push(route);
119 }
120
121 pub fn load_from_dir(&mut self, dir: &Path) -> Result<()> {
123 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()))? {
124 let entry = entry.map_err(|e| nargo_types::Error::external_error("server".to_string(), e.to_string(), nargo_types::Span::unknown()))?;
125 let path = entry.path();
126 if path.extension().map_or(false, |ext| ext == "json") {
127 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()))?;
128 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()))?;
129 self.routes.extend(routes);
130 }
131 }
132 Ok(())
133 }
134
135 pub fn routes_count(&self) -> usize {
137 self.routes.len()
138 }
139
140 pub async fn start(&self, port: u16) -> Result<()> {
142 println!("Mock server running on port {}...", port);
143 println!("Loaded {} routes", self.routes.len());
144 Ok(())
145 }
146}