Skip to content
This repository has been archived by the owner on Dec 21, 2024. It is now read-only.

Commit

Permalink
refactor: move global config to meta config
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanFlurry committed Jul 17, 2024
1 parent 8d0ab65 commit 8dc0d48
Show file tree
Hide file tree
Showing 21 changed files with 107 additions and 261 deletions.
4 changes: 2 additions & 2 deletions rivet-toolchain/src/backend/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub async fn provision_database(
.await?;

// Fetch remote DB URL
let mut global_project_config = config::global::mutate_project(|config| {
let mut global_project_config = config::meta::mutate_project(|config| {
config
.opengb
.projects
Expand Down Expand Up @@ -49,7 +49,7 @@ pub async fn provision_database(
env_config.url = db_url_res.url;

// Update cache
config::global::try_mutate_project(|config| {
config::meta::try_mutate_project(|config| {
// Was inserted in last `mutate_project` call
let project = unwrap!(config.opengb.projects.get_mut(&project_id));

Expand Down
4 changes: 2 additions & 2 deletions rivet-toolchain/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ pub mod database;
use global_error::prelude::*;
use rivet_api::{apis, models};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fs::File, io::Write, path::PathBuf, str::FromStr};
use std::{collections::HashMap, io::Write, path::PathBuf};
use tempfile::NamedTempFile;
use tokio::{fs, process::Command, signal};
use tokio::{process::Command};

use crate::{
config,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{collections::HashMap, path::PathBuf};

use global_error::prelude::*;
use rivet_api::models;
use serde::{Deserialize, Serialize};
use tokio::{
fs,
Expand All @@ -13,66 +12,38 @@ use crate::paths;

/// Configuration stored globally on the file system.
#[derive(Default, Serialize, Deserialize)]
pub struct GlobalConfig {
pub struct Meta {
/// Store project meta by the absolute path to the project.
pub project_roots: HashMap<PathBuf, ProjectMeta>,
pub projects: HashMap<PathBuf, ProjectMeta>,
}

/// Config stored in .rivet/config.json. Used to store persistent data.
#[derive(Default, Serialize, Deserialize)]
/// Config stored in .rivet/meta.json. Used to store persistent data, such as tokens & cache.
#[derive(Serialize, Deserialize)]
pub struct ProjectMeta {
#[serde(default)]
pub cluster: Cluster,
#[serde(default)]
pub telemetry: Telemetry,
#[serde(default)]
pub tokens: Tokens,
#[serde(default)]
pub opengb: OpenGb,
}

#[derive(Default, Serialize, Deserialize)]
pub struct Cluster {
#[serde(default)]
pub api_endpoint: Option<String>,
impl ProjectMeta {
fn new(api_endpoint: String, cloud_token: String) -> Self {
ProjectMeta {
cluster: Cluster { api_endpoint },
tokens: Tokens { cloud: cloud_token },
opengb: OpenGb::default(),
}
}
}

#[derive(Default, Serialize, Deserialize)]
pub struct Telemetry {
#[serde(default)]
pub disabled: bool,
pub struct Cluster {
pub api_endpoint: String,
}

#[derive(Default, Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct Tokens {
/// Cloud token used to authenticate all API requests.
///
/// If none provided, will be prompted for token on `rivet init`.
#[serde(default)]
pub cloud: Option<String>,

/// List of cached public namespace tokens.
#[serde(default)]
pub public_namespace: Vec<PublicNamespaceToken>,

/// List of cached development tokens. Before creating a new token, this list will be checked
/// for an existing token.
#[serde(default)]
pub development: Vec<DevelopmentToken>,
}

#[derive(Default, Serialize, Deserialize)]
pub struct PublicNamespaceToken {
pub namespace_name_id: String,
pub token: String,
}

#[derive(Default, Serialize, Deserialize)]
pub struct DevelopmentToken {
pub namespace_name_id: String,
pub hostname: String,
pub ports: HashMap<String, models::CloudMatchmakerDevelopmentPort>,
pub token: String,
pub cloud: String,
}

#[derive(Default, Serialize, Deserialize)]
Expand All @@ -93,19 +64,19 @@ pub struct OpenGbEnv {
pub url: Option<String>,
}

static SINGLETON: OnceCell<Mutex<GlobalConfig>> = OnceCell::const_new();
static SINGLETON: OnceCell<Mutex<Meta>> = OnceCell::const_new();

/// Gets the global config instance.
///
/// Use `read` to read properties from the config.
async fn get_or_init() -> GlobalResult<&'static Mutex<GlobalConfig>> {
async fn get_or_init() -> GlobalResult<&'static Mutex<Meta>> {
SINGLETON
.get_or_try_init::<GlobalError, _, _>(|| async {
let path = paths::global_config_file()?;
let path = paths::meta_config_file()?;

let config = match fs::read_to_string(&path).await {
Ok(config) => serde_json::from_str(&config).map_err(Into::<GlobalError>::into)?,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => GlobalConfig::default(),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Meta::default(),
Err(err) => return Err(err.into()),
};

Expand All @@ -117,17 +88,15 @@ async fn get_or_init() -> GlobalResult<&'static Mutex<GlobalConfig>> {
/// Writes the config to the file system.
///
/// Use `mutate` to make changes to the config publicly.
async fn write(config: &GlobalConfig) -> GlobalResult<()> {
fs::create_dir_all(paths::global_config_dir()?).await?;
fs::write(paths::global_config_file()?, serde_json::to_string(config)?).await?;
async fn write(config: &Meta) -> GlobalResult<()> {
fs::create_dir_all(paths::user_config_dir()?).await?;
fs::write(paths::meta_config_file()?, serde_json::to_string(config)?).await?;

Ok(())
}

/// Reads from the global config.
pub async fn try_read_global<F: FnOnce(&GlobalConfig) -> GlobalResult<T>, T>(
cb: F,
) -> GlobalResult<T> {
pub async fn try_read_global<F: FnOnce(&Meta) -> GlobalResult<T>, T>(cb: F) -> GlobalResult<T> {
let singleton = get_or_init().await?;
let mut lock = singleton.lock().await;

Expand All @@ -145,10 +114,10 @@ pub async fn try_read_project<F: FnOnce(&ProjectMeta) -> GlobalResult<T>, T>(
) -> GlobalResult<T> {
let project_root = paths::project_root()?;
try_read_global(|config| {
if let Some(project_config) = config.project_roots.get(&project_root) {
if let Some(project_config) = config.projects.get(&project_root) {
cb(project_config)
} else {
cb(&ProjectMeta::default())
bail!("project not initiated")
}
})
.await
Expand All @@ -159,7 +128,7 @@ pub async fn read_project<F: FnOnce(&ProjectMeta) -> T, T>(cb: F) -> GlobalResul
try_read_project(|x| Ok(cb(x))).await
}

pub async fn try_mutate_global<F: FnOnce(&mut GlobalConfig) -> GlobalResult<T>, T>(
pub async fn try_mutate_global<F: FnOnce(&mut Meta) -> GlobalResult<T>, T>(
cb: F,
) -> GlobalResult<T> {
let singleton = get_or_init().await?;
Expand All @@ -182,7 +151,10 @@ pub async fn try_mutate_project<F: FnOnce(&mut ProjectMeta) -> GlobalResult<T>,
) -> GlobalResult<T> {
let project_root = paths::project_root()?;
try_mutate_global(|config| {
let project_config = config.project_roots.entry(project_root).or_default();
let project_config = unwrap!(
config.projects.get_mut(&project_root),
"project meta does not exist"
);
cb(project_config)
})
.await
Expand All @@ -192,3 +164,29 @@ pub async fn try_mutate_project<F: FnOnce(&mut ProjectMeta) -> GlobalResult<T>,
pub async fn mutate_project<F: FnOnce(&mut ProjectMeta) -> T, T>(cb: F) -> GlobalResult<T> {
try_mutate_project(|x| Ok(cb(x))).await
}

pub async fn has_project() -> GlobalResult<bool> {
let project_root = paths::project_root()?;
let has_project = try_read_global(|meta| Ok(meta.projects.contains_key(&project_root))).await?;
Ok(has_project)
}

pub async fn insert_project(api_endpoint: String, cloud_token: String) -> GlobalResult<()> {
let project_root = paths::project_root()?;
try_mutate_global(|meta| {
Ok(meta
.projects
.insert(project_root, ProjectMeta::new(api_endpoint, cloud_token)))
})
.await?;
Ok(())
}

pub async fn delete_project() -> GlobalResult<()> {
let project_root = paths::project_root()?;
try_mutate_global(|x| {
x.projects.remove(&project_root);
Ok(())
})
.await
}
2 changes: 1 addition & 1 deletion rivet-toolchain/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod global;
pub mod meta;
pub mod settings;
15 changes: 4 additions & 11 deletions rivet-toolchain/src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ pub fn user_agent() -> String {
format!("CLI/{VERSION}")
}

pub const DEFAULT_API_ENDPOINT: &'static str = "https://api.rivet.gg";

pub type Ctx = Arc<CtxInner>;

pub struct CtxInner {
Expand All @@ -32,21 +30,16 @@ pub struct CtxInner {

pub async fn load() -> GlobalResult<Ctx> {
let (api_endpoint, token) =
config::global::read_project(|x| (x.cluster.api_endpoint.clone(), x.tokens.cloud.clone()))
config::meta::read_project(|x| (x.cluster.api_endpoint.clone(), x.tokens.cloud.clone()))
.await?;
let token = unwrap!(token);
init(api_endpoint, token).await
}

pub async fn init(api_endpoint: Option<String>, access_token: String) -> GlobalResult<Ctx> {
let api_endpoint = api_endpoint
.clone()
.unwrap_or_else(|| DEFAULT_API_ENDPOINT.to_string());

pub async fn init(api_endpoint: String, cloud_token: String) -> GlobalResult<Ctx> {
// Create OpenAPI config
let openapi_config_cloud = apis::configuration::Configuration {
base_path: api_endpoint.clone(),
bearer_access_token: Some(access_token.clone()),
bearer_access_token: Some(cloud_token.clone()),
user_agent: Some(user_agent()),
..Default::default()
};
Expand Down Expand Up @@ -78,7 +71,7 @@ pub async fn init(api_endpoint: Option<String>, access_token: String) -> GlobalR

Ok(Arc::new(CtxInner {
api_endpoint,
access_token,
access_token: cloud_token,
game_id: game_id.to_string(),
bootstrap: bootstrap_response,
openapi_config_cloud,
Expand Down
8 changes: 4 additions & 4 deletions rivet-toolchain/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ pub fn project_root() -> GlobalResult<PathBuf> {
Ok(env::current_dir()?)
}

pub fn global_config_dir() -> GlobalResult<PathBuf> {
pub fn user_config_dir() -> GlobalResult<PathBuf> {
Ok(unwrap!(dirs::config_dir()).join("rivet"))
}

pub fn global_config_file() -> GlobalResult<PathBuf> {
Ok(global_config_dir()?.join("config.json"))
pub fn meta_config_file() -> GlobalResult<PathBuf> {
Ok(user_config_dir()?.join("meta.json"))
}

pub fn user_settings_config_file() -> GlobalResult<PathBuf> {
Ok(global_config_dir()?.join("settings.json"))
Ok(user_config_dir()?.join("settings.json"))
}

pub fn project_settings_config_file() -> GlobalResult<PathBuf> {
Expand Down
14 changes: 6 additions & 8 deletions rivet-toolchain/src/tasks/check_login_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::{config, util::task::TaskCtx};
pub struct Input {}

#[derive(Serialize)]
pub struct Output {}
pub struct Output {
logged_in: bool,
}

pub struct Task;

Expand All @@ -19,12 +21,8 @@ impl super::Task for Task {
"check_login_state"
}

async fn run(task: TaskCtx, input: Input) -> GlobalResult<Output> {
let has_token = config::global::read_project(|x| x.tokens.cloud.is_some()).await?;
if !has_token {
bail!("No Rivet token found, please do the sign in process");
}

Ok(Output {})
async fn run(_task: TaskCtx, _input: Input) -> GlobalResult<Output> {
let logged_in = config::meta::has_project().await?;
Ok(Output { logged_in })
}
}
6 changes: 2 additions & 4 deletions rivet-toolchain/src/tasks/deploy/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use tokio::fs;

use crate::{backend, config, ctx::Ctx, util::net::upload, util::task::TaskCtx};

const OPENGB_NO_MINIFY: bool = false;

pub struct DeployOpts {
/// The environment to deploy to.
pub environment_id: String,
Expand Down Expand Up @@ -44,7 +42,7 @@ pub async fn deploy(ctx: &Ctx, task: TaskCtx, opts: DeployOpts) -> GlobalResult<
task.log_stdout(format!("[Building Project] {}", project_path.display()));

// Build
let mut cmd_env = config::settings::try_read(|settings| {
let cmd_env = config::settings::try_read(|settings| {
let mut env = settings.backend.command_environment.clone();
env.extend(settings.backend.deploy.command_environment.clone());
Ok(env)
Expand Down Expand Up @@ -75,7 +73,7 @@ pub async fn deploy(ctx: &Ctx, task: TaskCtx, opts: DeployOpts) -> GlobalResult<
)
.await?;

let db_url = config::global::try_read_project(|config| {
let db_url = config::meta::try_read_project(|config| {
let project = unwrap!(config.opengb.projects.get(&project.project_id));
let env = unwrap!(project.environments.get(&env.environment_id));

Expand Down
4 changes: 2 additions & 2 deletions rivet-toolchain/src/tasks/deploy/game_server.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use global_error::prelude::*;
use std::{collections::HashMap, path::Path};
use std::{path::Path};
use uuid::Uuid;

use crate::{
config,
ctx::Ctx,
util::{
cmd::{self, shell_cmd},
docker::{self, generate_unique_image_tag, BuildCompression, BuildKind},
docker::{self, generate_unique_image_tag, BuildCompression},
task::TaskCtx,
},
};
Expand Down
2 changes: 1 addition & 1 deletion rivet-toolchain/src/tasks/get_bootstrap_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl super::Task for Task {
"get_bootstrap_data"
}

async fn run(task: TaskCtx, input: Self::Input) -> GlobalResult<Self::Output> {
async fn run(_task: TaskCtx, _input: Self::Input) -> GlobalResult<Self::Output> {
let ctx = crate::ctx::load().await?;
Ok(Output {
token: ctx.access_token.clone(),
Expand Down
2 changes: 1 addition & 1 deletion rivet-toolchain/src/tasks/get_hub_link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl super::Task for Task {
"get_hub_link"
}

async fn run(task: TaskCtx, input: Self::Input) -> GlobalResult<Self::Output> {
async fn run(_task: TaskCtx, _input: Self::Input) -> GlobalResult<Self::Output> {
bail!("todo")
}
}
3 changes: 1 addition & 2 deletions rivet-toolchain/src/tasks/open.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use global_error::prelude::*;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

use crate::{paths, util::task::TaskCtx};
use crate::{util::task::TaskCtx};

#[derive(Deserialize)]
pub struct Input {
Expand Down
Loading

0 comments on commit 8dc0d48

Please sign in to comment.