1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use cloudflare::endpoints::workerskv::WorkersKvNamespace;
use cloudflare::framework::response::ApiFailure;

use crate::http;
use crate::settings::global_user::GlobalUser;
use crate::settings::toml::Target;

use super::create;
use super::list;

pub enum UpsertedNamespace {
    Created(WorkersKvNamespace),
    Reused(WorkersKvNamespace),
}

pub fn upsert(
    target: &Target,
    user: &GlobalUser,
    title: String,
) -> Result<UpsertedNamespace, failure::Error> {
    let client = http::cf_v4_client(user)?;
    let response = create(&client, &target.account_id, &title);

    match response {
        Ok(success) => Ok(UpsertedNamespace::Created(success.result)),
        Err(e) => match &e {
            ApiFailure::Error(_status, api_errors) => {
                if api_errors.errors.iter().any(|e| e.code == 10014) {
                    log::info!("Namespace {} already exists.", title);

                    match list(&client, target)?
                        .iter()
                        .find(|ns| ns.title == title) {
                        Some(namespace) => Ok(UpsertedNamespace::Reused(namespace.to_owned())),
                        None => failure::bail!("namespace already exists, but could not be found in the API's listed namespaces"),
                    }
                } else {
                    failure::bail!("{}", http::format_error(e, Some(&error_suggestions)))
                }
            }
            _ => failure::bail!("{}", http::format_error(e, Some(&error_suggestions))),
        },
    }
}

fn error_suggestions(code: u16) -> &'static str {
    match code {
        10014 => "Namespace already exists, try using a different namespace.",
        10037 => "Edit your API Token to have correct permissions, or use the 'Edit Cloudflare Workers' API Token template.",
        _ => "",
    }
}