Skip to content

Commit 2398e44

Browse files
committed
add config parsing
1 parent 4b99126 commit 2398e44

File tree

8 files changed

+148
-9
lines changed

8 files changed

+148
-9
lines changed

Cargo.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ bpaf = "0.4.3"
1212
toml = "0.5"
1313
log = "0.4"
1414
simple_logger = "2.1.0"
15+
serde = { version = "1.0", features = ["derive"] }
1516
futures = "0.3"

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ⚙️ cobalt
2+
3+
cobalt is a simple, minimal reverse proxy in rust using tokio. It's the greatly improved descendant of the earlier [pine](https://github.com/blobcode/pine).
4+
5+
## installation
6+
7+
To install, you'll need `cargo` and `git` installed.
8+
9+
## getting started
10+
11+
## config
12+
13+
---
14+
15+
written with ❤️ by [blobcode](https://blobco.de)

cobalt.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
port = 8080
1+
port = 8000
22

33
[[host]]
4-
from = ["localhost:8080"]
4+
from = ["localhost:8000"]
55
to = "localhost:4000"

src/args.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use bpaf::*;
2+
use std::path::PathBuf;
3+
#[derive(Clone, Debug)]
4+
pub struct Opts {
5+
pub path: PathBuf,
6+
}
7+
8+
pub fn parse() -> Opts {
9+
let path = short('c')
10+
.long("config")
11+
.help("path to config file")
12+
.argument("PATH")
13+
.from_str();
14+
15+
// combine parsers `speed` and `distance` parsers into a parser for Opts
16+
let parser = construct!(Opts { path });
17+
18+
// define help message, attach it to parser, and run the results
19+
Info::default()
20+
.descr("a simple reverse proxy")
21+
.for_parser(parser)
22+
.run()
23+
}

src/config.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use serde::Deserialize;
2+
use std::path::PathBuf;
3+
use std::{collections::HashMap, fs};
4+
5+
// main config struct
6+
pub struct Config {
7+
pub port: u16,
8+
pub hosts: HashMap<String, String>,
9+
}
10+
11+
// structs that parse toml
12+
#[derive(Deserialize)]
13+
pub struct ConfigToml {
14+
pub port: u16,
15+
pub host: Vec<HostToml>,
16+
}
17+
18+
#[derive(Deserialize)]
19+
pub struct HostToml {
20+
pub from: Vec<String>,
21+
pub to: String,
22+
}
23+
24+
// parse config file
25+
fn parsehosts(config: ConfigToml) -> HashMap<String, String> {
26+
// parse list
27+
let mut hosts = HashMap::new();
28+
// add all "to" and "from" fields to the hashmap
29+
for host in config.host {
30+
for from in host.from {
31+
let to = &host.to;
32+
hosts.insert(from.to_string(), to.to_string());
33+
}
34+
}
35+
hosts
36+
}
37+
38+
// main function to get config struct
39+
pub fn parse(file: PathBuf) -> Config {
40+
// load config
41+
let buf = fs::read_to_string(file).unwrap();
42+
43+
// parse file contents
44+
let config: ConfigToml = toml::from_str(&buf).unwrap();
45+
46+
// create main config struct
47+
Config {
48+
port: config.port,
49+
hosts: parsehosts(config),
50+
}
51+
}

src/main.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
use simple_logger::SimpleLogger;
22
use std::error::Error;
33

4+
mod args;
5+
mod config;
46
mod server;
57

68
#[tokio::main]
79
async fn main() -> Result<(), Box<dyn Error>> {
810
// logging setup
911
SimpleLogger::new().init().unwrap();
1012

13+
// get args
14+
let opts = args::parse();
15+
16+
// get config
17+
let config = config::parse(opts.path);
18+
1119
// server setup
12-
let server = server::Server { port: 80 };
20+
let server = server::Server { port: config.port };
1321
server.run().await?;
1422
Ok(())
1523
}

src/server.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,25 @@ use futures::FutureExt;
66
use std::error::Error;
77

88
pub struct Server {
9-
pub port: u32,
9+
pub port: u16,
1010
}
1111

1212
impl Server {
1313
pub async fn run(&self) -> Result<(), Box<dyn Error>> {
14-
let listen_addr = "127.0.0.1:8081".to_string();
15-
let server_addr = "127.0.0.1:8080".to_string();
14+
let listen_addr = "127.0.0.1:".to_string() + &self.port.to_string();
1615

1716
log::info!("Listening on: {}", listen_addr);
18-
log::info!("Proxying to: {}", server_addr);
1917

2018
let listener = TcpListener::bind(listen_addr).await?;
2119

2220
while let Ok((inbound, _)) = listener.accept().await {
23-
let transfer = proxy(inbound, server_addr.clone()).map(|r| {
21+
let handler = handle(inbound).map(|r| {
2422
if let Err(e) = r {
2523
log::error!("Failed to proxy; error={}", e);
2624
}
2725
});
2826

29-
tokio::spawn(transfer);
27+
tokio::spawn(handler);
3028
}
3129
Ok(())
3230
}
@@ -52,3 +50,31 @@ async fn proxy(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box<dyn
5250

5351
Ok(())
5452
}
53+
54+
async fn handle(inbound: TcpStream) -> Result<(), Box<dyn Error>> {
55+
let server_addr = "127.0.0.1:8080".to_string();
56+
57+
let transfer = proxy(inbound, server_addr.clone()).map(|r| {
58+
if let Err(e) = r {
59+
log::error!("Failed to proxy; error={}", e);
60+
}
61+
});
62+
63+
tokio::spawn(transfer);
64+
65+
Ok(())
66+
}
67+
68+
fn gethost() -> Result<(), Box<dyn Error>> {
69+
let mut headers = [httparse::EMPTY_HEADER; 64];
70+
let mut req = httparse::Request::new(&mut headers);
71+
72+
let buf = b"GET /index.html HTTP/1.1\r\nHost";
73+
assert!(req.parse(buf)?.is_partial());
74+
75+
// a partial request, so we try again once we have more data
76+
77+
let buf = b"GET /index.html HTTP/1.1\r\nHost: example.domain\r\n\r\n";
78+
assert!(req.parse(buf)?.is_complete());
79+
Ok(())
80+
}

0 commit comments

Comments
 (0)