Skip to content

Commit

Permalink
Rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
kim committed Aug 10, 2023
1 parent 9011a7c commit 387dcea
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 152 deletions.
19 changes: 1 addition & 18 deletions crates/bindings/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use spacetimedb_lib::{
name::{UniqueDomainName, UniqueTld},
Address, DataKey, Hash, Identity,
};
use spacetimedb_lib::{Address, DataKey, Hash, Identity};

use super::PrimaryKey;
use crate::{FilterableValue, UniqueValue};
Expand Down Expand Up @@ -64,17 +61,3 @@ impl UniqueValue for Address {
todo!()
}
}

impl FilterableValue for UniqueDomainName {}
impl UniqueValue for UniqueDomainName {
fn into_primarykey(self) -> PrimaryKey {
todo!()
}
}

impl FilterableValue for UniqueTld {}
impl UniqueValue for UniqueTld {
fn into_primarykey(self) -> PrimaryKey {
todo!()
}
}
24 changes: 13 additions & 11 deletions crates/client-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ use spacetimedb::address::Address;
use spacetimedb::auth::identity::{DecodingKey, EncodingKey};
use spacetimedb::client::ClientActorIndex;
use spacetimedb::database_instance_context_controller::DatabaseInstanceContextController;
use spacetimedb::hash::Hash;
use spacetimedb::host::UpdateDatabaseResult;
use spacetimedb::host::{EnergyQuanta, HostController, UpdateDatabaseResult};
use spacetimedb::host::{EnergyQuanta, HostController};
use spacetimedb::identity::Identity;
use spacetimedb::messages::control_db::{Database, DatabaseInstance, EnergyBalance, IdentityEmail, Node};
use spacetimedb::messages::control_db::{Database, DatabaseInstance, IdentityEmail, Node};
use spacetimedb::messages::worker_db::DatabaseInstanceState;
use spacetimedb::module_host_context::ModuleHostContext;
use spacetimedb::sendgrid_controller::SendGridController;
Expand Down Expand Up @@ -112,7 +111,7 @@ pub trait ControlStateReadAccess {
fn get_recovery_codes(&self, email: &str) -> spacetimedb::control_db::Result<Vec<RecoveryCode>>;

// Energy
fn get_energy_balance(&self, identity: &Identity) -> spacetimedb::control_db::Result<Option<EnergyBalance>>;
fn get_energy_balance(&self, identity: &Identity) -> spacetimedb::control_db::Result<Option<EnergyQuanta>>;

// DNS
fn lookup_address(&self, domain: &DomainName) -> spacetimedb::control_db::Result<Option<Address>>;
Expand Down Expand Up @@ -152,7 +151,7 @@ pub trait ControlStateWriteAccess: Send + Sync {
) -> spacetimedb::control_db::Result<()>;

// Energy
async fn add_energy(&self, identity: &Identity, quanta: u64) -> spacetimedb::control_db::Result<()>;
async fn add_energy(&self, identity: &Identity, amount: EnergyQuanta) -> spacetimedb::control_db::Result<()>;
async fn withdraw_energy(&self, identity: &Identity, amount: EnergyQuanta) -> spacetimedb::control_db::Result<()>;

// DNS
Expand Down Expand Up @@ -221,7 +220,7 @@ impl<T: ControlStateReadAccess + ?Sized> ControlStateReadAccess for ArcEnv<T> {
}

// Energy
fn get_energy_balance(&self, identity: &Identity) -> spacetimedb::control_db::Result<Option<EnergyBalance>> {
fn get_energy_balance(&self, identity: &Identity) -> spacetimedb::control_db::Result<Option<EnergyQuanta>> {
self.0.get_energy_balance(identity)
}

Expand Down Expand Up @@ -270,8 +269,8 @@ impl<T: ControlStateWriteAccess + ?Sized> ControlStateWriteAccess for ArcEnv<T>
self.0.insert_recovery_code(identity, email, code).await
}

async fn add_energy(&self, identity: &Identity, quanta: u64) -> spacetimedb::control_db::Result<()> {
self.0.add_energy(identity, quanta).await
async fn add_energy(&self, identity: &Identity, amount: EnergyQuanta) -> spacetimedb::control_db::Result<()> {
self.0.add_energy(identity, amount).await
}
async fn withdraw_energy(&self, identity: &Identity, amount: EnergyQuanta) -> spacetimedb::control_db::Result<()> {
self.0.withdraw_energy(identity, amount).await
Expand Down Expand Up @@ -375,7 +374,7 @@ impl<T: ControlStateReadAccess + ?Sized> ControlStateReadAccess for Arc<T> {
}

// Energy
fn get_energy_balance(&self, identity: &Identity) -> spacetimedb::control_db::Result<Option<EnergyBalance>> {
fn get_energy_balance(&self, identity: &Identity) -> spacetimedb::control_db::Result<Option<EnergyQuanta>> {
(**self).get_energy_balance(identity)
}

Expand Down Expand Up @@ -424,8 +423,11 @@ impl<T: ControlStateWriteAccess + ?Sized> ControlStateWriteAccess for Arc<T> {
(**self).insert_recovery_code(identity, email, code).await
}

async fn add_energy(&self, identity: &Identity, quanta: u64) -> spacetimedb::control_db::Result<()> {
(**self).add_energy(identity, quanta).await
async fn add_energy(&self, identity: &Identity, amount: EnergyQuanta) -> spacetimedb::control_db::Result<()> {
(**self).add_energy(identity, amount).await
}
async fn withdraw_energy(&self, identity: &Identity, amount: EnergyQuanta) -> spacetimedb::control_db::Result<()> {
(**self).withdraw_energy(identity, amount).await
}

async fn register_tld(&self, identity: &Identity, tld: Tld) -> spacetimedb::control_db::Result<RegisterTldResult> {
Expand Down
52 changes: 19 additions & 33 deletions crates/client-api/src/routes/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ pub async fn call<S: ControlStateDelegate + NodeDelegate>(

let args = ReducerArgs::Json(body);

let address = name_or_address.resolve(&*worker_ctx).await?.into();
let database = worker_ctx_find_database(&*worker_ctx, &address).await?.ok_or_else(|| {
let address = name_or_address.resolve(&worker_ctx).await?.into();
let database = worker_ctx_find_database(&worker_ctx, &address).await?.ok_or_else(|| {
log::error!("Could not find database: {}", address.to_hex());
(StatusCode::NOT_FOUND, "No such database.")
})?;
Expand Down Expand Up @@ -157,7 +157,7 @@ use rand::Rng;
use spacetimedb::auth::identity::encode_token;
use spacetimedb::sql::execute::execute;
use spacetimedb_lib::identity::AuthCtx;
use spacetimedb_lib::name::{DnsLookupResponse, PublishOp, PublishResult};
use spacetimedb_lib::name::{DnsLookupResponse, PublishResult};
use spacetimedb_lib::recovery::{RecoveryCode, RecoveryCodeResponse};
use std::convert::From;

Expand Down Expand Up @@ -255,8 +255,8 @@ pub async fn describe<S>(
where
S: ControlStateDelegate + NodeDelegate,
{
let address = name_or_address.resolve(&*worker_ctx).await?.into();
let database = worker_ctx_find_database(&*worker_ctx, &address)
let address = name_or_address.resolve(&worker_ctx).await?.into();
let database = worker_ctx_find_database(&worker_ctx, &address)
.await?
.ok_or((StatusCode::NOT_FOUND, "No such database."))?;

Expand Down Expand Up @@ -312,8 +312,8 @@ pub async fn catalog<S>(
where
S: ControlStateDelegate + NodeDelegate,
{
let address = name_or_address.resolve(&*worker_ctx).await?.into();
let database = worker_ctx_find_database(&*worker_ctx, &address)
let address = name_or_address.resolve(&worker_ctx).await?.into();
let database = worker_ctx_find_database(&worker_ctx, &address)
.await?
.ok_or((StatusCode::NOT_FOUND, "No such database."))?;

Expand Down Expand Up @@ -358,8 +358,8 @@ pub async fn info<S: ControlStateDelegate>(
State(worker_ctx): State<S>,
Path(InfoParams { name_or_address }): Path<InfoParams>,
) -> axum::response::Result<impl IntoResponse> {
let address = name_or_address.resolve(&*worker_ctx).await?.into();
let database = worker_ctx_find_database(&*worker_ctx, &address)
let address = name_or_address.resolve(&worker_ctx).await?.into();
let database = worker_ctx_find_database(&worker_ctx, &address)
.await?
.ok_or((StatusCode::NOT_FOUND, "No such database."))?;

Expand Down Expand Up @@ -410,8 +410,8 @@ where
// Should all the others change?
let auth = auth_or_unauth(auth)?;

let address = name_or_address.resolve(&*worker_ctx).await?.into();
let database = worker_ctx_find_database(&*worker_ctx, &address)
let address = name_or_address.resolve(&worker_ctx).await?.into();
let database = worker_ctx_find_database(&worker_ctx, &address)
.await?
.ok_or((StatusCode::NOT_FOUND, "No such database."))?;

Expand Down Expand Up @@ -484,10 +484,10 @@ fn mime_ndjson() -> mime::Mime {
}

async fn worker_ctx_find_database(
worker_ctx: &dyn WorkerCtx,
worker_ctx: &(impl ControlStateDelegate + ?Sized),
address: &Address,
) -> Result<Option<Database>, StatusCode> {
worker_ctx.get_database_by_address(address).await.map_err(log_and_500)
worker_ctx.get_database_by_address(address).map_err(log_and_500)
}

#[derive(Deserialize)]
Expand All @@ -512,8 +512,8 @@ where
// which queries this identity is allowed to execute against the database.
let auth = auth.get().ok_or((StatusCode::UNAUTHORIZED, "Invalid credentials."))?;

let address = name_or_address.resolve(&*worker_ctx).await?.into();
let database = worker_ctx_find_database(&*worker_ctx, &address)
let address = name_or_address.resolve(&worker_ctx).await?.into();
let database = worker_ctx_find_database(&worker_ctx, &address)
.await?
.ok_or((StatusCode::NOT_FOUND, "No such database."))?;

Expand Down Expand Up @@ -631,11 +631,7 @@ pub async fn register_tld<S: ControlStateDelegate>(
let auth = auth_or_bad_request(auth)?;

let tld = tld.parse::<DomainName>().map_err(DomainParsingRejection)?.into();
let result = ctx
.control_db()
.spacetime_register_tld(tld, auth.identity)
.await
.map_err(log_and_500)?;
let result = ctx.register_tld(&auth.identity, tld).await.map_err(log_and_500)?;
Ok(axum::Json(result))
}

Expand Down Expand Up @@ -746,13 +742,6 @@ pub async fn confirm_recovery_code<S: ControlStateDelegate + NodeDelegate>(
Ok(axum::Json(result))
}

async fn control_ctx_find_database(ctx: &dyn ControlCtx, address: &Address) -> Result<Option<Database>, StatusCode> {
ctx.control_db()
.get_database_by_address(address)
.await
.map_err(log_and_500)
}

#[derive(Deserialize)]
pub struct PublishDatabaseParams {}

Expand Down Expand Up @@ -793,7 +782,7 @@ pub async fn publish<S: NodeDelegate + ControlStateDelegate>(

let (db_addr, db_name) = match name_or_address {
Some(noa) => match noa.try_resolve(&ctx).await? {
Ok((addr, maybe_domain)) => (addr, maybe_domain),
Ok(resolved) => resolved.into(),
Err(domain) => {
// `name_or_address` was a `NameOrAddress::Name`, but no record
// exists yet. Create it now with a fresh address.
Expand Down Expand Up @@ -923,10 +912,7 @@ pub async fn set_name<S: ControlStateDelegate>(

/// This API call is just designed to allow clients to determine whether or not they can
/// establish a connection to SpacetimeDB. This API call doesn't actually do anything.
pub async fn ping(
State(_ctx): State<Arc<dyn ControlCtx>>,
_auth: SpacetimeAuthHeader,
) -> axum::response::Result<impl IntoResponse> {
pub async fn ping<S>(State(_ctx): State<S>, _auth: SpacetimeAuthHeader) -> axum::response::Result<impl IntoResponse> {
Ok(())
}

Expand All @@ -939,7 +925,7 @@ where
.route("/dns/:database_name", get(dns::<S>))
.route("/reverse_dns/:database_address", get(reverse_dns::<S>))
.route("/set_name", get(set_name::<S>))
.route("/ping", get(ping))
.route("/ping", get(ping::<S>))
.route("/register_tld", get(register_tld::<S>))
.route("/request_recovery_code", get(request_recovery_code::<S>))
.route("/confirm_recovery_code", get(confirm_recovery_code::<S>))
Expand Down
83 changes: 60 additions & 23 deletions crates/client-api/src/routes/energy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,53 @@ pub async fn get_energy_balance<S: ControlStateDelegate>(

#[derive(Deserialize)]
pub struct AddEnergyQueryParams {
quanta: Option<u64>,
amount: Option<String>,
}
pub async fn add_energy<S: ControlStateDelegate>(
State(ctx): State<S>,
Path(IdentityParams { identity }): Path<IdentityParams>,
Query(AddEnergyQueryParams { quanta }): Query<AddEnergyQueryParams>,
Query(AddEnergyQueryParams { amount }): Query<AddEnergyQueryParams>,
auth: SpacetimeAuthHeader,
) -> axum::response::Result<impl IntoResponse> {
// TODO: we need to do authorization here. For now, just short-circuit. GOD MODE.

if let Some(satoshi) = quanta {
ctx.add_energy(&identity, satoshi).await.map_err(log_and_500)?;
let Some(auth) = auth.auth else {
return Err(StatusCode::UNAUTHORIZED.into());
};
// Nb.: Negative amount withdraws
let amount = amount.map(|s| s.parse::<i128>()).transpose().map_err(|e| {
log::error!("Failed to parse amount: {e:?}");
StatusCode::BAD_REQUEST
})?;

let mut balance = ctx
.get_energy_balance(&auth.identity)
.map_err(log_and_500)?
.map(|quanta| quanta.0)
.unwrap_or(0);

if let Some(satoshi) = amount {
ctx.add_energy(&auth.identity, EnergyQuanta(satoshi))
.await
.map_err(log_and_500)?;
balance += satoshi;
}
get_budget_inner(ctx, &identity)

let response_json = json!({
// Note: balance must be returned as a string to avoid truncation.
"balance": balance.to_string(),
});

Ok(axum::Json(response_json))
}

fn get_budget_inner(ctx: impl ControlStateDelegate, identity: &Identity) -> axum::response::Result<impl IntoResponse> {
let budget = ctx
let balance = ctx
.get_energy_balance(identity)
.map_err(log_and_500)?
.unwrap_or(EnergyQuanta(0));
.map(|quanta| quanta.0)
.unwrap_or(0);

let response_json = json!({
// Note: balance must be returned as a string to avoid truncation.
"balance": balance.0.to_string(),
"balance": balance.to_string(),
});

Ok(axum::Json(response_json))
Expand All @@ -60,8 +83,8 @@ fn get_budget_inner(ctx: impl ControlStateDelegate, identity: &Identity) -> axum
pub struct SetEnergyBalanceQueryParams {
balance: Option<String>,
}
pub async fn set_energy_balance(
State(ctx): State<Arc<dyn ControlCtx>>,
pub async fn set_energy_balance<S: ControlStateDelegate>(
State(ctx): State<S>,
Path(IdentityParams { identity }): Path<IdentityParams>,
Query(SetEnergyBalanceQueryParams { balance }): Query<SetEnergyBalanceQueryParams>,
auth: SpacetimeAuthHeader,
Expand All @@ -80,23 +103,37 @@ pub async fn set_energy_balance(

let identity = Identity::from(identity);

let balance = balance
let desired_balance = balance
.map(|balance| balance.parse::<i128>())
.transpose()
.map_err(|err| {
log::error!("Failed to parse balance: {:?}", err);
StatusCode::BAD_REQUEST
})?;
let balance = EnergyQuanta(balance.unwrap_or(0));

ctx.control_db()
.set_energy_balance(identity, balance)
.await
.map_err(log_and_500)?;
})?
.unwrap_or(0);
let current_balance = ctx
.get_energy_balance(&identity)
.map_err(log_and_500)?
.map(|quanta| quanta.0)
.unwrap_or(0);

let balance: i128 = if desired_balance > current_balance {
let delta = desired_balance - current_balance;
ctx.add_energy(&identity, EnergyQuanta(delta))
.await
.map_err(log_and_500)?;
delta
} else {
let delta = current_balance - desired_balance;
ctx.withdraw_energy(&identity, EnergyQuanta(delta))
.await
.map_err(log_and_500)?;
delta
};

let response_json = json!({
// Note: balance must be returned as a string to avoid truncation.
"balance": balance.0.to_string(),
"balance": balance.to_string(),
});

Ok(axum::Json(response_json))
Expand All @@ -106,7 +143,7 @@ pub fn router<S>() -> axum::Router<S>
where
S: NodeDelegate + ControlStateDelegate + Clone + 'static,
{
use axum::routing::{get, post};
use axum::routing::{get, post, put};
axum::Router::new()
.route("/:identity", get(get_energy_balance::<S>))
.route("/:identity", post(set_energy_balance::<S>))
Expand Down
2 changes: 1 addition & 1 deletion crates/client-api/src/routes/subscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where
{
let auth = auth.get_or_create(&ctx).await?;

let address = name_or_address.resolve(&*worker_ctx).await?.into();
let address = name_or_address.resolve(&ctx).await?.into();

let (res, ws_upgrade, protocol) =
ws.select_protocol([(BIN_PROTOCOL, Protocol::Binary), (TEXT_PROTOCOL, Protocol::Text)]);
Expand Down
6 changes: 6 additions & 0 deletions crates/client-api/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,9 @@ impl From<ResolvedAddress> for Address {
value.address
}
}

impl From<ResolvedAddress> for (Address, Option<DomainName>) {
fn from(ResolvedAddress { address, domain }: ResolvedAddress) -> Self {
(address, domain)
}
}
Loading

0 comments on commit 387dcea

Please sign in to comment.