Skip to content

Commit 45523eb

Browse files
committed
wip: initial cloudfront support
1 parent aa74b7d commit 45523eb

File tree

14 files changed

+704
-62
lines changed

14 files changed

+704
-62
lines changed

Cargo.lock

Lines changed: 135 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: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ aws-sdk-route53 = { version = "1.0", optional = true }
2222
aws-sdk-ssm = { version = "1.0", optional = true }
2323
axum = "0.7.5"
2424
base64 = "0.22"
25+
chrono = "0.4"
2526
clap = { version = "4.5.4", features = ["string", "derive", "env"] }
2627
rust-embed = { version = "8.4.0", features = ["axum", "debug-embed"] }
2728
futures = "0.3.30"
2829
indicatif = "0.17"
2930
mime_guess = "2.0"
31+
nix = { version = "0.29", features = ["net"] }
3032
rand = "0.8"
3133
reqwest = "0.12"
3234
serde = { version = "1.0.203", features = ["derive"] }
@@ -44,4 +46,10 @@ reqwest = { version = "0.12.4", features = ["blocking"] }
4446

4547
[features]
4648
cloudflare = []
47-
aws = ["dep:aws-config", "dep:aws-sdk-ec2", "dep:aws-sdk-cloudformation", "dep:aws-sdk-route53", "dep:aws-sdk-ssm"]
49+
aws = [
50+
"dep:aws-config",
51+
"dep:aws-sdk-ec2",
52+
"dep:aws-sdk-cloudformation",
53+
"dep:aws-sdk-route53",
54+
"dep:aws-sdk-ssm",
55+
]

examples/ui_aws.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ async fn index() -> Html<String> {
2222
public_ip: "203.0.113.42".to_string(),
2323
private_ip: "172.17.0.1".to_string(),
2424
state: "running".to_string(),
25-
launch_time: "2025-11-11 19:30:00 UTC".to_string(),
25+
launch_time: "2025-11-11T19:30:00Z".to_string(),
26+
uptime: String::new(), // Will be calculated dynamically
2627
});
2728

2829
let template = IndexTemplate {
2930
tunnel_stats: stats,
3031
proxy_info,
32+
cloudfront_info: None,
3133
};
3234

3335
Html(template.render().unwrap())

examples/ui_high_traffic.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use outpost::api::{IndexTemplate, ProxyInfo, TunnelStats};
44

55
async fn index() -> Html<String> {
66
let mut stats = TunnelStats {
7-
bytes_sent: 500_000_000_000, // 465 GB
8-
bytes_received: 1_200_000_000_000, // 1.09 TB
7+
bytes_sent: 500_000_000_000, // 465 GB
8+
bytes_received: 1_200_000_000_000, // 1.09 TB
99
bytes_sent_formatted: String::new(),
1010
bytes_received_formatted: String::new(),
1111
packets_sent: 5_678_901,
@@ -22,12 +22,14 @@ async fn index() -> Html<String> {
2222
public_ip: "198.51.100.123".to_string(),
2323
private_ip: "172.17.0.1".to_string(),
2424
state: "running".to_string(),
25-
launch_time: "2025-10-12 08:15:00 UTC".to_string(),
25+
launch_time: "2025-10-12T08:15:00Z".to_string(),
26+
uptime: String::new(), // Will be calculated dynamically
2627
});
2728

2829
let template = IndexTemplate {
2930
tunnel_stats: stats,
3031
proxy_info,
32+
cloudfront_info: None,
3133
};
3234

3335
Html(template.render().unwrap())

src/api.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct Assets;
1818
pub struct AppState {
1919
pub stats: Arc<RwLock<TunnelStats>>,
2020
pub proxy_info: Arc<RwLock<Option<ProxyInfo>>>,
21+
pub cloudfront_info: Arc<RwLock<Option<CloudFrontInfo>>>,
2122
}
2223

2324
#[derive(Clone, Default)]
@@ -72,6 +73,31 @@ fn format_bytes(bytes: u64) -> String {
7273
}
7374
}
7475

76+
/// Calculate uptime from a launch time string in RFC3339 format
77+
pub fn calculate_uptime(launch_time: &str) -> String {
78+
use chrono::{DateTime, Utc};
79+
80+
// Try to parse the launch time
81+
if let Ok(launch) = DateTime::parse_from_rfc3339(launch_time) {
82+
let now = Utc::now();
83+
let duration = now.signed_duration_since(launch.with_timezone(&Utc));
84+
85+
let days = duration.num_days();
86+
let hours = duration.num_hours() % 24;
87+
let minutes = duration.num_minutes() % 60;
88+
89+
if days > 0 {
90+
format!("{}d {}h {}m", days, hours, minutes)
91+
} else if hours > 0 {
92+
format!("{}h {}m", hours, minutes)
93+
} else {
94+
format!("{}m", minutes)
95+
}
96+
} else {
97+
"Unknown".to_string()
98+
}
99+
}
100+
75101
#[derive(Clone)]
76102
pub enum ProxyInfo {
77103
Aws {
@@ -82,6 +108,7 @@ pub enum ProxyInfo {
82108
private_ip: String,
83109
state: String,
84110
launch_time: String,
111+
uptime: String,
85112
},
86113
Cloudflare {
87114
hostname: String,
@@ -101,6 +128,7 @@ impl ProxyInfo {
101128
private_ip: "172.17.0.1".to_string(),
102129
state: "running".to_string(),
103130
launch_time: "2025-11-11 19:30:00 UTC".to_string(),
131+
uptime: "2h 15m".to_string(),
104132
}
105133
}
106134

@@ -114,11 +142,30 @@ impl ProxyInfo {
114142
}
115143
}
116144

145+
#[derive(Clone, Default)]
146+
pub struct CloudFrontInfo {
147+
pub distribution_id: String,
148+
pub distribution_domain: String,
149+
pub status: String,
150+
}
151+
152+
impl CloudFrontInfo {
153+
/// Create example CloudFront info for demo mode
154+
pub fn example() -> Self {
155+
CloudFrontInfo {
156+
distribution_id: "E1234ABCDEFGHI".to_string(),
157+
distribution_domain: "d1234abcdefghi.cloudfront.net".to_string(),
158+
status: "Deployed".to_string(),
159+
}
160+
}
161+
}
162+
117163
#[derive(Template)]
118164
#[template(path = "index.html")]
119165
pub struct IndexTemplate {
120166
pub tunnel_stats: TunnelStats,
121167
pub proxy_info: Option<ProxyInfo>,
168+
pub cloudfront_info: Option<CloudFrontInfo>,
122169
}
123170

124171
pub async fn assets(axum::extract::Path(file): axum::extract::Path<String>) -> Response {
@@ -148,11 +195,23 @@ pub fn router(state: AppState) -> Router {
148195
pub async fn index(State(state): State<AppState>) -> impl IntoResponse {
149196
let mut stats = state.stats.read().await.clone();
150197
stats.format_sizes();
151-
let proxy_info = state.proxy_info.read().await.clone();
198+
let mut proxy_info = state.proxy_info.read().await.clone();
199+
let cloudfront_info = state.cloudfront_info.read().await.clone();
200+
201+
// Calculate uptime dynamically for AWS proxy
202+
if let Some(ProxyInfo::Aws {
203+
launch_time,
204+
uptime,
205+
..
206+
}) = &mut proxy_info
207+
{
208+
*uptime = calculate_uptime(launch_time);
209+
}
152210

153211
let template = IndexTemplate {
154212
tunnel_stats: stats,
155213
proxy_info,
214+
cloudfront_info,
156215
};
157216

158217
Html(template.render().unwrap())

0 commit comments

Comments
 (0)