Skip to content

Commit 1614b22

Browse files
committed
refactor: Add SafeUrlPart
1 parent 9c31adb commit 1614b22

6 files changed

Lines changed: 173 additions & 65 deletions

File tree

activity/fly-http/impl/src/app.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use crate::exports::obelisk_flyio::activity_fly_http::apps;
2-
use crate::{API_BASE_URL, AppSlug, OrgSlug, request_with_api_token};
2+
use crate::{API_BASE_URL, AppName, OrgSlug, request_with_api_token};
33
use anyhow::anyhow;
44
use serde::{Deserialize, Serialize};
55
use wstd::http::request::JsonRequest as _;
66
use wstd::http::{Client, Method, StatusCode};
77
use wstd::runtime::block_on;
88

9-
async fn get(app_name: AppSlug) -> Result<Option<apps::App>, anyhow::Error> {
9+
async fn get(app_name: AppName) -> Result<Option<apps::App>, anyhow::Error> {
1010
let request = request_with_api_token()?
1111
.method(Method::GET)
1212
.uri(format!("{API_BASE_URL}/apps/{app_name}"))
@@ -28,7 +28,7 @@ async fn get(app_name: AppSlug) -> Result<Option<apps::App>, anyhow::Error> {
2828
}
2929
}
3030

31-
async fn put(org_slug: String, app_name: String) -> Result<apps::App, anyhow::Error> {
31+
async fn put(org_slug: OrgSlug, app_name: AppName) -> Result<apps::App, anyhow::Error> {
3232
let client = Client::new();
3333

3434
// Attempt to create the app
@@ -39,8 +39,8 @@ async fn put(org_slug: String, app_name: String) -> Result<apps::App, anyhow::Er
3939
}
4040

4141
let request_body = CreateAppRequest {
42-
app_name: &app_name,
43-
org_slug: &org_slug,
42+
app_name: app_name.as_ref(),
43+
org_slug: org_slug.as_ref(),
4444
};
4545

4646
let post_request = request_with_api_token()?
@@ -57,7 +57,7 @@ async fn put(org_slug: String, app_name: String) -> Result<apps::App, anyhow::Er
5757
}
5858
let app_response: AppResponse = response.body_mut().json().await?;
5959
return Ok(apps::App {
60-
name: app_name,
60+
name: app_name.to_string(),
6161
id: app_response.id,
6262
});
6363
}
@@ -91,7 +91,7 @@ async fn put(org_slug: String, app_name: String) -> Result<apps::App, anyhow::Er
9191
let app_details: AppDetails = get_response.body_mut().json().await?;
9292

9393
// Verify the organization slug matches
94-
if app_details.organization.slug == org_slug {
94+
if app_details.organization.slug == org_slug.as_ref() {
9595
// Idempotency success: App exists and is in the correct org.
9696
return Ok(apps::App {
9797
id: app_details.id,
@@ -116,7 +116,7 @@ async fn put(org_slug: String, app_name: String) -> Result<apps::App, anyhow::Er
116116
))
117117
}
118118

119-
async fn list(org_slug: String) -> Result<Vec<apps::App>, anyhow::Error> {
119+
async fn list(org_slug: OrgSlug) -> Result<Vec<apps::App>, anyhow::Error> {
120120
let request = request_with_api_token()?
121121
.method(Method::GET)
122122
.uri(format!("{API_BASE_URL}/apps?org_slug={org_slug}"))
@@ -140,7 +140,7 @@ async fn list(org_slug: String) -> Result<Vec<apps::App>, anyhow::Error> {
140140
}
141141
}
142142

143-
async fn delete(app_name: String, force: bool) -> Result<(), anyhow::Error> {
143+
async fn delete(app_name: AppName, force: bool) -> Result<(), anyhow::Error> {
144144
let mut url = format!("{API_BASE_URL}/apps/{app_name}");
145145
if force {
146146
url.push_str("?force=true");
@@ -166,21 +166,34 @@ async fn delete(app_name: String, force: bool) -> Result<(), anyhow::Error> {
166166
impl apps::Guest for crate::Component {
167167
fn get(app_name: String) -> Result<Option<apps::App>, String> {
168168
(|| {
169-
let app_slug = AppSlug::new(app_name)?;
170-
block_on(get(app_slug))
169+
let app_name = AppName::new(app_name)?;
170+
block_on(get(app_name))
171171
})()
172172
.map_err(|err| err.to_string())
173173
}
174174

175175
fn put(org_slug: String, app_name: String) -> Result<apps::App, String> {
176-
block_on(put(org_slug, app_name)).map_err(|err| err.to_string())
176+
(|| {
177+
let org_slug = OrgSlug::new(org_slug)?;
178+
let app_name = AppName::new(app_name)?;
179+
block_on(put(org_slug, app_name))
180+
})()
181+
.map_err(|err| err.to_string())
177182
}
178183

179184
fn list(org_slug: String) -> Result<Vec<apps::App>, String> {
180-
block_on(list(org_slug)).map_err(|err| err.to_string())
185+
(|| {
186+
let org_slug = OrgSlug::new(org_slug)?;
187+
block_on(list(org_slug))
188+
})()
189+
.map_err(|err| err.to_string())
181190
}
182191

183192
fn delete(app_name: String, force: bool) -> Result<(), String> {
184-
block_on(delete(app_name, force)).map_err(|err| err.to_string())
193+
(|| {
194+
let app_name = AppName::new(app_name)?;
195+
block_on(delete(app_name, force))
196+
})()
197+
.map_err(|err| err.to_string())
185198
}
186199
}

activity/fly-http/impl/src/lib.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ fn request_with_api_token() -> Result<request::Builder, anyhow::Error> {
2424

2525
#[derive(derive_more::Display)]
2626
#[display("{value}")]
27-
struct SlugOf<T> {
27+
struct SafeUrlPart<T> {
2828
value: String,
2929
_phantom_data: PhantomData<T>,
3030
}
31-
impl<T> SlugOf<T> {
32-
fn new(s: String) -> Result<SlugOf<T>, anyhow::Error> {
33-
if s.chars()
34-
.all(|c| c.is_ascii_lowercase() || c.is_numeric() || c == '-')
35-
{
36-
Ok(SlugOf {
31+
impl<T> SafeUrlPart<T> {
32+
fn new(s: String) -> Result<SafeUrlPart<T>, anyhow::Error> {
33+
if s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') {
34+
Ok(SafeUrlPart {
3735
value: s,
3836
_phantom_data: PhantomData::default(),
3937
})
@@ -42,8 +40,19 @@ impl<T> SlugOf<T> {
4240
}
4341
}
4442
}
43+
impl<T> AsRef<str> for SafeUrlPart<T> {
44+
fn as_ref(&self) -> &str {
45+
&self.value
46+
}
47+
}
4548

4649
struct AppMarker;
47-
type AppSlug = SlugOf<AppMarker>;
50+
type AppName = SafeUrlPart<AppMarker>;
4851
struct OrgMarker;
49-
type OrgSlug = SlugOf<OrgMarker>;
52+
type OrgSlug = SafeUrlPart<OrgMarker>;
53+
struct SecretKeyMarker;
54+
type SecretKey = SafeUrlPart<SecretKeyMarker>;
55+
struct VolumeIdMarker;
56+
type VolumeId = SafeUrlPart<VolumeIdMarker>;
57+
struct MachineIdMarker;
58+
type MachineId = SafeUrlPart<MachineIdMarker>;

activity/fly-http/impl/src/machine.rs

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::obelisk_flyio::activity_fly_http::regions::Region;
55

66
use crate::machine::ser::MachineSer;
77
use crate::serde::KebabWrapper;
8-
use crate::{API_BASE_URL, Component, request_with_api_token};
8+
use crate::{API_BASE_URL, AppName, Component, MachineId, request_with_api_token};
99
use anyhow::{Context, anyhow, bail, ensure};
1010
use ser::{
1111
ExecResponseSer, MachineConfigSer, MachineCreateRequestSer, MachineCreateResponseSer,
@@ -313,7 +313,7 @@ pub(crate) mod ser {
313313
}
314314
}
315315

316-
async fn list(app_name: String) -> Result<Vec<Machine>, anyhow::Error> {
316+
async fn list(app_name: AppName) -> Result<Vec<Machine>, anyhow::Error> {
317317
let url = format!("{API_BASE_URL}/apps/{app_name}/machines");
318318
let request = request_with_api_token()?
319319
.method(Method::GET)
@@ -337,7 +337,7 @@ async fn list(app_name: String) -> Result<Vec<Machine>, anyhow::Error> {
337337
}
338338
}
339339

340-
async fn get(app_name: String, machine_id: String) -> Result<Option<Machine>, anyhow::Error> {
340+
async fn get(app_name: AppName, machine_id: MachineId) -> Result<Option<Machine>, anyhow::Error> {
341341
let url = format!("{API_BASE_URL}/apps/{app_name}/machines/{machine_id}");
342342
let request = request_with_api_token()?
343343
.method(Method::GET)
@@ -364,7 +364,7 @@ async fn get(app_name: String, machine_id: String) -> Result<Option<Machine>, an
364364
}
365365

366366
async fn create(
367-
app_name: String,
367+
app_name: AppName,
368368
machine_name: String,
369369
machine_config: MachineConfig,
370370
region: Option<Region>,
@@ -420,8 +420,8 @@ async fn create(
420420
}
421421

422422
async fn update(
423-
app_name: String,
424-
machine_id: String,
423+
app_name: AppName,
424+
machine_id: MachineId,
425425
machine_config: MachineConfig,
426426
region: Option<Region>,
427427
) -> Result<(), anyhow::Error> {
@@ -449,7 +449,7 @@ async fn update(
449449
)
450450
})?;
451451
ensure!(
452-
resp.id == machine_id,
452+
resp.id == machine_id.as_ref(),
453453
"unexpected id returned, expected {machine_id} got {id}",
454454
id = resp.id
455455
);
@@ -462,8 +462,8 @@ async fn update(
462462
}
463463

464464
async fn exec(
465-
app_name: String,
466-
machine_id: String,
465+
app_name: AppName,
466+
machine_id: MachineId,
467467
command: Vec<String>,
468468
) -> Result<ExecResponse, anyhow::Error> {
469469
let url = format!("{API_BASE_URL}/apps/{app_name}/machines/{machine_id}/exec");
@@ -493,14 +493,23 @@ async fn exec(
493493
}
494494

495495
async fn change_machine(
496-
app_name: String,
497-
machine_id: String,
496+
app_name: AppName,
497+
machine_id: MachineId,
498498
url_suffix: &'static str,
499499
) -> Result<(), anyhow::Error> {
500500
let url = format!("{API_BASE_URL}/apps/{app_name}/machines/{machine_id}/{url_suffix}");
501501
send_request(url, Method::POST).await
502502
}
503503

504+
async fn delete(
505+
app_name: AppName,
506+
machine_id: MachineId,
507+
force: bool,
508+
) -> Result<(), anyhow::Error> {
509+
let url = format!("{API_BASE_URL}/apps/{app_name}/machines/{machine_id}?force={force}");
510+
send_request(url, Method::DELETE).await
511+
}
512+
504513
async fn send_request(url: String, method: Method) -> Result<(), anyhow::Error> {
505514
let request = request_with_api_token()?
506515
.method(method)
@@ -514,7 +523,6 @@ async fn send_request(url: String, method: Method) -> Result<(), anyhow::Error>
514523
} else {
515524
let error_status = response.status();
516525
let error_body = response.into_body().bytes().await?;
517-
eprintln!("Got error status {error_status}");
518526
Err(anyhow!(
519527
"failed with status {error_status}: {}",
520528
String::from_utf8_lossy(&error_body)
@@ -525,11 +533,20 @@ async fn send_request(url: String, method: Method) -> Result<(), anyhow::Error>
525533
// Implementation of the vm interface for the component.
526534
impl Guest for Component {
527535
fn list(app_name: String) -> Result<Vec<Machine>, String> {
528-
block_on(list(app_name)).map_err(|err| err.to_string())
536+
(|| {
537+
let app_name = AppName::new(app_name)?;
538+
block_on(list(app_name))
539+
})()
540+
.map_err(|err| err.to_string())
529541
}
530542

531543
fn get(app_name: String, machine_id: String) -> Result<Option<Machine>, String> {
532-
block_on(get(app_name, machine_id)).map_err(|err| err.to_string())
544+
(|| {
545+
let app_name = AppName::new(app_name)?;
546+
let machine_id = MachineId::new(machine_id)?;
547+
block_on(get(app_name, machine_id))
548+
})()
549+
.map_err(|err| err.to_string())
533550
}
534551

535552
fn create(
@@ -538,8 +555,11 @@ impl Guest for Component {
538555
machine_config: MachineConfig,
539556
region: Option<Region>,
540557
) -> Result<String, String> {
541-
block_on(create(app_name, machine_name, machine_config, region))
542-
.map_err(|err| err.to_string())
558+
(|| {
559+
let app_name = AppName::new(app_name)?;
560+
block_on(create(app_name, machine_name, machine_config, region))
561+
})()
562+
.map_err(|err| err.to_string())
543563
}
544564

545565
fn update(
@@ -548,37 +568,70 @@ impl Guest for Component {
548568
machine_config: MachineConfig,
549569
region: Option<Region>,
550570
) -> Result<(), String> {
551-
block_on(update(app_name, machine_id, machine_config, region))
552-
.map_err(|err| err.to_string())
571+
(|| {
572+
let app_name = AppName::new(app_name)?;
573+
let machine_id = MachineId::new(machine_id)?;
574+
block_on(update(app_name, machine_id, machine_config, region))
575+
})()
576+
.map_err(|err| err.to_string())
553577
}
554578

555579
fn stop(app_name: String, machine_id: String) -> Result<(), String> {
556-
block_on(change_machine(app_name, machine_id, "stop")).map_err(|err| err.to_string())
580+
(|| {
581+
let app_name = AppName::new(app_name)?;
582+
let machine_id = MachineId::new(machine_id)?;
583+
block_on(change_machine(app_name, machine_id, "stop"))
584+
})()
585+
.map_err(|err| err.to_string())
557586
}
558587

559588
fn suspend(app_name: String, machine_id: String) -> Result<(), String> {
560-
block_on(change_machine(app_name, machine_id, "suspend")).map_err(|err| err.to_string())
589+
(|| {
590+
let app_name = AppName::new(app_name)?;
591+
let machine_id = MachineId::new(machine_id)?;
592+
block_on(change_machine(app_name, machine_id, "suspend"))
593+
})()
594+
.map_err(|err| err.to_string())
561595
}
562596

563597
fn start(app_name: String, machine_id: String) -> Result<(), String> {
564-
block_on(change_machine(app_name, machine_id, "start")).map_err(|err| err.to_string())
598+
(|| {
599+
let app_name = AppName::new(app_name)?;
600+
let machine_id = MachineId::new(machine_id)?;
601+
block_on(change_machine(app_name, machine_id, "start"))
602+
})()
603+
.map_err(|err| err.to_string())
565604
}
566605

567606
fn restart(app_name: String, machine_id: String) -> Result<(), String> {
568-
block_on(change_machine(app_name, machine_id, "restart")).map_err(|err| err.to_string())
607+
(|| {
608+
let app_name = AppName::new(app_name)?;
609+
let machine_id = MachineId::new(machine_id)?;
610+
block_on(change_machine(app_name, machine_id, "restart"))
611+
})()
612+
.map_err(|err| err.to_string())
569613
}
570614

571615
fn delete(app_name: String, machine_id: String, force: bool) -> Result<(), String> {
572-
let url = format!("{API_BASE_URL}/apps/{app_name}/machines/{machine_id}?force={force}");
573-
block_on(send_request(url, Method::DELETE)).map_err(|err| err.to_string())
616+
(|| {
617+
let app_name = AppName::new(app_name)?;
618+
let machine_id = MachineId::new(machine_id)?;
619+
block_on(delete(app_name, machine_id, force))
620+
})()
621+
.map_err(|err| err.to_string())
574622
}
575623

576624
fn exec(
577625
app_name: String,
578626
machine_id: String,
579627
command: Vec<String>,
580628
) -> Result<ExecResponse, String> {
581-
block_on(exec(app_name, machine_id, command)).map_err(|err| err.to_string())
629+
(|| {
630+
let app_name = AppName::new(app_name)?;
631+
let machine_id = MachineId::new(machine_id)?;
632+
block_on(exec(app_name, machine_id, command))
633+
})()
634+
.map_err(|err| err.to_string())
582635
}
583636
}
584637

0 commit comments

Comments
 (0)