Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #914 from cloudflare/alewis/multi-route
Browse files Browse the repository at this point in the history
Refactor: Use cloudflare-rs for calls to routes endpoints
  • Loading branch information
ashleymichal authored Nov 27, 2019
2 parents 7ec421d + 61ae823 commit efbc96a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 88 deletions.
5 changes: 2 additions & 3 deletions src/commands/publish/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ mod route;
pub mod upload_form;

pub use package::Package;

use route::Route;
use route::{publish_route, Route};

use std::env;
use std::path::Path;
Expand Down Expand Up @@ -110,7 +109,7 @@ fn publish_script(

let pattern = if target.route.is_some() {
let route = Route::new(&target)?;
Route::publish(&user, &target, &route)?;
publish_route(&user, &target, &route)?;
log::info!("publishing to route");
route.pattern
} else {
Expand Down
147 changes: 63 additions & 84 deletions src/commands/publish/route.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
use crate::http;
use serde::{Deserialize, Serialize};

use cloudflare::endpoints::workers::{CreateRoute, CreateRouteParams, ListRoutes, WorkersRoute};
use cloudflare::framework::apiclient::ApiClient;
use cloudflare::framework::HttpApiClientConfig;

use crate::http::{api_client, format_error};
use crate::settings::global_user::GlobalUser;
use crate::settings::target::Target;
use crate::terminal::emoji;
use reqwest::header::CONTENT_TYPE;
use serde::{Deserialize, Serialize};

use log::info;

#[derive(Deserialize, Serialize)]
#[derive(Deserialize, PartialEq, Serialize)]
pub struct Route {
script: Option<String>,
pub pattern: String,
}

#[derive(Deserialize)]
struct RoutesResponse {
result: Vec<Route>,
impl From<&WorkersRoute> for Route {
fn from(api_route: &WorkersRoute) -> Route {
Route {
script: api_route.script.clone(),
pattern: api_route.pattern.clone(),
}
}
}

impl Route {
Expand All @@ -28,103 +34,76 @@ impl Route {
{
failure::bail!("You must provide a zone_id in your wrangler.toml before publishing!");
}
let msg_config_error = format!("{} Your project config has an error, check your `wrangler.toml`: `route` must be provided.", emoji::WARN);
let msg_config_error = format!(
"{} Your project config has an error, check your `wrangler.toml`: `route` must be provided.",
emoji::WARN
);
Ok(Route {
script: Some(target.name.to_string()),
pattern: target.route.clone().expect(&msg_config_error),
})
}
}

pub fn publish(
user: &GlobalUser,
target: &Target,
route: &Route,
) -> Result<(), failure::Error> {
if route.exists(user, target)? {
return Ok(());
}
pub fn publish_route(
user: &GlobalUser,
target: &Target,
route: &Route,
) -> Result<(), failure::Error> {
if route_exists(user, target, route)? {
Ok(())
} else {
create(user, target, route)
}
}

pub fn exists(&self, user: &GlobalUser, target: &Target) -> Result<bool, failure::Error> {
let routes = get_routes(user, target)?;
fn route_exists(user: &GlobalUser, target: &Target, route: &Route) -> Result<bool, failure::Error> {
let routes = get_routes(user, target)?;

for route in routes {
if route.matches(self) {
return Ok(true);
}
for remote_route in routes {
if remote_route == *route {
return Ok(true);
}
Ok(false)
}

pub fn matches(&self, route: &Route) -> bool {
self.pattern == route.pattern && self.script == route.script
}
Ok(false)
}

fn get_routes(user: &GlobalUser, target: &Target) -> Result<Vec<Route>, failure::Error> {
let routes_addr = get_routes_addr(target)?;

let client = http::auth_client(None, user);

let mut res = client.get(&routes_addr).send()?;

if !res.status().is_success() {
let msg = format!(
"{} There was an error fetching your project's routes.\n Status Code: {}\n Msg: {}",
emoji::WARN,
res.status(),
res.text()?
);
failure::bail!(msg)
}
let client = api_client(user, HttpApiClientConfig::default())?;

let routes_response: RoutesResponse = serde_json::from_str(&res.text()?)?;
let routes: Vec<Route> = match client.request(&ListRoutes {
zone_identifier: &target.zone_id.as_ref().unwrap(),
}) {
Ok(success) => success.result.iter().map(|r| Route::from(r)).collect(),
Err(e) => failure::bail!("{}", format_error(e, None)), // TODO: add suggestion fn
};

Ok(routes_response.result)
Ok(routes)
}

fn create(user: &GlobalUser, target: &Target, route: &Route) -> Result<(), failure::Error> {
let client = http::auth_client(None, user);
let body = serde_json::to_string(&route)?;

let routes_addr = get_routes_addr(target)?;

info!("Creating your route {:#?}", &route.pattern,);
let mut res = client
.post(&routes_addr)
.header(CONTENT_TYPE, "application/json")
.body(body)
.send()?;

if !res.status().is_success() {
let msg;
if res.status().as_u16() == 10020 {
msg = format!(
"{} A worker with a different name was previously deployed to `{}`. If you would like to overwrite that worker, you will need to change `name` in your `wrangler.toml` to match the currently deployed worker, or navigate to https://dash.cloudflare.com/workers and rename or delete that worker.\n",
emoji::WARN,
serde_json::to_string(&route)?
);
} else {
msg = format!(
"{} There was an error creating your route.\n Status Code: {}\n Msg: {}",
emoji::WARN,
res.status(),
res.text()?
);
}

failure::bail!(msg)
let client = api_client(user, HttpApiClientConfig::default())?;

log::info!("Creating your route {:#?}", &route.pattern,);
match client.request(&CreateRoute {
zone_identifier: &target.zone_id.as_ref().unwrap(),
params: CreateRouteParams {
pattern: route.pattern.clone(),
script: route.script.clone(),
},
}) {
Ok(_) => Ok(()),
Err(e) => failure::bail!("{}", format_error(e, Some(&routes_error_help))),
}
Ok(())
}

fn get_routes_addr(target: &Target) -> Result<String, failure::Error> {
if let Some(zone_id) = &target.zone_id {
return Ok(format!(
"https://api.cloudflare.com/client/v4/zones/{}/workers/routes",
zone_id
));
fn routes_error_help(error_code: u16) -> &'static str {
match error_code {
10020 => r#"
A worker with a different name was previously deployed to the specified route.
If you would like to overwrite that worker,
you will need to change `name` in your `wrangler.toml` to match the currently deployed worker,
or navigate to https://dash.cloudflare.com/workers and rename or delete that worker.\n"#,
_ => "",
}
failure::bail!("You much provide a zone_id in your wrangler.toml.")
}
2 changes: 1 addition & 1 deletion src/settings/global_user.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use cloudflare::framework::auth::Credentials;
Expand Down Expand Up @@ -147,6 +146,7 @@ pub fn get_global_config_path() -> Result<PathBuf, failure::Error> {
mod tests {
use super::*;
use std::fs::File;
use std::io::prelude::*;
use tempfile::tempdir;

use crate::settings::environment::MockEnvironment;
Expand Down

0 comments on commit efbc96a

Please sign in to comment.