Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update actor api #1306

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/api/actor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ user-identity-get = { path = "../../services/user-identity/ops/get" }
user-team-list = { path = "../../services/user/ops/team-list" }
rivet-config = { version = "0.1.0", path = "../../common/config" }
rivet-env = { version = "0.1.0", path = "../../common/env" }
game-resolve-name-id = { version = "0.0.1", path = "../../services/game/ops/resolve-name-id" }
game-namespace-resolve-name-id = { version = "0.0.1", path = "../../services/game/ops/namespace-resolve-name-id" }

[dev-dependencies]
rivet-connection = { path = "../../common/connection" }
Expand Down
2 changes: 1 addition & 1 deletion packages/api/actor/src/assert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::auth::Auth;
pub async fn server_for_env(
ctx: &Ctx<Auth>,
server_id: Uuid,
game_id: Uuid,
_game_id: Uuid,
env_id: Uuid,
) -> GlobalResult<()> {
let servers_res = ctx
Expand Down
46 changes: 36 additions & 10 deletions packages/api/actor/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ use proto::claims::Claims;
use rivet_claims::ClaimsDecode;
use rivet_operation::prelude::*;

use crate::route::GlobalQuery;

pub struct Auth {
config: rivet_config::Config,
claims: Option<Claims>,
}

pub struct CheckOutput {
pub game_id: Uuid,
pub env_id: Uuid,
}

#[async_trait]
impl ApiAuth for Auth {
async fn new(
Expand All @@ -21,7 +27,6 @@ impl ApiAuth for Auth {
Self::rate_limit(&config, rate_limit_ctx).await?;

Ok(Auth {
config: config.clone(),
claims: if let Some(api_token) = api_token {
Some(as_auth_expired(rivet_claims::decode(
&config.server()?.jwt.public,
Expand Down Expand Up @@ -52,15 +57,36 @@ impl Auth {
self.claims()?.as_env_service()
}

pub async fn check_game(
pub async fn check(
&self,
ctx: &OperationContext<()>,
game_id: Uuid,
env_id: Uuid,
query: &GlobalQuery,
allow_service: bool,
) -> GlobalResult<()> {
) -> GlobalResult<CheckOutput> {
let claims = self.claims()?;

// Lookup project name ID
let project = unwrap_with!(query.project(), GAME_NOT_FOUND);
let game_res = op!([ctx] game_resolve_name_id {
name_ids: vec![project.to_string()],
})
.await?;
let game = unwrap_with!(game_res.games.first(), GAME_NOT_FOUND);
let game_id = unwrap!(game.game_id).as_uuid();

// Lookup environment name ID
let environment = unwrap_with!(query.environment(), GAME_ENVIRONMENT_NOT_FOUND);
let env_res = op!([ctx] game_namespace_resolve_name_id {
game_id: game.game_id,
name_ids: vec![environment.to_string()],
})
.await?;
let env = unwrap_with!(env_res.namespaces.first(), GAME_ENVIRONMENT_NOT_FOUND);
let env_id = unwrap!(env.namespace_id).as_uuid();

// Build output
let output = CheckOutput { game_id, env_id };

// Get the game this env belongs to
let ns_res = op!([ctx] game_namespace_get {
namespace_ids: vec![env_id.into()],
Expand All @@ -81,7 +107,7 @@ impl Auth {
API_FORBIDDEN,
reason = "Cloud token cannot write to this game",
);
Ok(())
Ok(output)
} else if let Ok(service_ent) = claims.as_env_service() {
ensure_with!(
allow_service,
Expand All @@ -93,7 +119,7 @@ impl Auth {
API_FORBIDDEN,
reason = "Service token cannot write to this game",
);
Ok(())
Ok(output)
} else if let Ok(user_ent) = claims.as_user() {
// Get the user
let (user_res, game_res, team_list_res) = tokio::try_join!(
Expand All @@ -114,7 +140,7 @@ impl Auth {

// Allow admin
if user.is_admin {
return Ok(());
return Ok(output);
}

// Verify user is not deleted
Expand Down Expand Up @@ -142,7 +168,7 @@ impl Auth {
reasons = util_team::format_deactivate_reasons(&dev_team.deactivate_reasons)?,
);

Ok(())
Ok(output)
} else {
bail_with!(
CLAIMS_MISSING_ENTITLEMENT,
Expand Down
1 change: 1 addition & 0 deletions packages/api/actor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod assert;
pub mod auth;
pub mod route;
pub mod utils;
96 changes: 72 additions & 24 deletions packages/api/actor/src/route/actors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,26 @@ use api_helper::{anchor::WatchIndexQuery, ctx::Ctx};
use rivet_api::models;
use rivet_convert::{ApiInto, ApiTryInto};
use rivet_operation::prelude::*;
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use serde_json::json;
use std::collections::HashMap;

use crate::{assert, auth::Auth};
use crate::{
assert,
auth::{Auth, CheckOutput},
utils::build_global_query_compat,
};

use super::GlobalQuery;

// MARK: GET /games/{}/environments/{}/actors/{}
pub async fn get(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
actor_id: Uuid,
_watch_index: WatchIndexQuery,
query: GlobalQuery,
) -> GlobalResult<models::ActorGetActorResponse> {
ctx.auth()
.check_game(ctx.op_ctx(), game_id, env_id, true)
.await?;
let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query, false).await?;

// Get the server
let servers_res = ctx
Expand All @@ -36,16 +39,24 @@ pub async fn get(
})
}

// MARK: POST /games/{}/environments/{}/actors
pub async fn create(
pub async fn get_deprecated(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
actor_id: Uuid,
watch_index: WatchIndexQuery,
) -> GlobalResult<models::ActorGetActorResponse> {
let global = build_global_query_compat(&ctx, game_id, env_id).await?;
get(ctx, actor_id, watch_index, global).await
}

// MARK: POST /games/{}/environments/{}/actors
pub async fn create(
ctx: Ctx<Auth>,
body: models::ActorCreateActorRequest,
query: GlobalQuery,
) -> GlobalResult<models::ActorCreateActorResponse> {
ctx.auth()
.check_game(ctx.op_ctx(), game_id, env_id, true)
.await?;
let CheckOutput { game_id, env_id } = ctx.auth().check(ctx.op_ctx(), &query, false).await?;

let (clusters_res, game_configs_res) = tokio::try_join!(
ctx.op(cluster::ops::get_for_game::Input {
Expand Down Expand Up @@ -175,22 +186,31 @@ pub async fn create(
})
}

pub async fn create_deprecated(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
body: models::ActorCreateActorRequest,
) -> GlobalResult<models::ActorCreateActorResponse> {
let global = build_global_query_compat(&ctx, game_id, env_id).await?;
create(ctx, body, global).await
}

// MARK: DELETE /games/{}/environments/{}/actors/{}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct DeleteQuery {
#[serde(flatten)]
global: GlobalQuery,
override_kill_timeout: Option<i64>,
}

pub async fn destroy(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
actor_id: Uuid,
query: DeleteQuery,
) -> GlobalResult<serde_json::Value> {
ctx.auth()
.check_game(ctx.op_ctx(), game_id, env_id, true)
.await?;
let CheckOutput { game_id, env_id } =
ctx.auth().check(ctx.op_ctx(), &query.global, false).await?;

assert::server_for_env(&ctx, actor_id, game_id, env_id).await?;

Expand Down Expand Up @@ -223,24 +243,41 @@ pub async fn destroy(
Ok(json!({}))
}

pub async fn destroy_deprecated(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
actor_id: Uuid,
query: DeleteQuery,
) -> GlobalResult<serde_json::Value> {
let global = build_global_query_compat(&ctx, game_id, env_id).await?;
destroy(
ctx,
actor_id,
DeleteQuery {
global,
override_kill_timeout: query.override_kill_timeout,
},
)
.await
}

// MARK: GET /games/{}/environments/{}/actors
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct ListQuery {
#[serde(flatten)]
global: GlobalQuery,
tags_json: Option<String>,
include_destroyed: Option<bool>,
cursor: Option<Uuid>,
}

pub async fn list_actors(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
_watch_index: WatchIndexQuery,
query: ListQuery,
) -> GlobalResult<models::ActorListActorsResponse> {
ctx.auth()
.check_game(ctx.op_ctx(), game_id, env_id, true)
.await?;
let CheckOutput { env_id, .. } = ctx.auth().check(ctx.op_ctx(), &query.global, false).await?;

let list_res = ctx
.op(ds::ops::server::list_for_env::Input {
Expand Down Expand Up @@ -268,3 +305,14 @@ pub async fn list_actors(

Ok(models::ActorListActorsResponse { actors: servers })
}

pub async fn list_actors_deprecated(
ctx: Ctx<Auth>,
game_id: Uuid,
env_id: Uuid,
watch_index: WatchIndexQuery,
query: ListQuery,
) -> GlobalResult<models::ActorListActorsResponse> {
let global = build_global_query_compat(&ctx, game_id, env_id).await?;
list_actors(ctx, watch_index, ListQuery { global, ..query }).await
}
Loading
Loading