forked from coracle/caravel
feat(infra): pass Blossom S3 config to Zooid with schema key prefix
This commit is contained in:
@@ -26,6 +26,13 @@ LIVEKIT_URL=
|
|||||||
LIVEKIT_API_KEY=
|
LIVEKIT_API_KEY=
|
||||||
LIVEKIT_API_SECRET=
|
LIVEKIT_API_SECRET=
|
||||||
|
|
||||||
|
# Blossom S3 (optional; when region, bucket, access key, and secret are all set, relays with blossom enabled sync with adapter s3 and key_prefix = relay schema)
|
||||||
|
BLOSSOM_S3_ENDPOINT=
|
||||||
|
BLOSSOM_S3_REGION=
|
||||||
|
BLOSSOM_S3_BUCKET=
|
||||||
|
BLOSSOM_S3_ACCESS_KEY=
|
||||||
|
BLOSSOM_S3_SECRET_KEY=
|
||||||
|
|
||||||
# Billing
|
# Billing
|
||||||
NWC_URL= # Nostr Wallet Connect URL for generating Lightning invoices
|
NWC_URL= # Nostr Wallet Connect URL for generating Lightning invoices
|
||||||
ENCRYPTION_SECRET= # Nostr secret key (hex or nsec) used to encrypt tenant NWC URLs at rest
|
ENCRYPTION_SECRET= # Nostr secret key (hex or nsec) used to encrypt tenant NWC URLs at rest
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ Environment variables:
|
|||||||
| `LIVEKIT_URL` | LiveKit URL sent to zooid when relay livekit is enabled | _optional_ |
|
| `LIVEKIT_URL` | LiveKit URL sent to zooid when relay livekit is enabled | _optional_ |
|
||||||
| `LIVEKIT_API_KEY` | LiveKit API key sent to zooid | _optional_ |
|
| `LIVEKIT_API_KEY` | LiveKit API key sent to zooid | _optional_ |
|
||||||
| `LIVEKIT_API_SECRET` | LiveKit API secret sent to zooid | _optional_ |
|
| `LIVEKIT_API_SECRET` | LiveKit API secret sent to zooid | _optional_ |
|
||||||
|
| `BLOSSOM_S3_ENDPOINT` | S3-compatible endpoint URL for Blossom; omit for AWS S3 | _optional_ |
|
||||||
|
| `BLOSSOM_S3_REGION` | S3 region; with bucket, access key, and secret enables S3 for Blossom | _optional_ |
|
||||||
|
| `BLOSSOM_S3_BUCKET` | S3 bucket name | _optional_ |
|
||||||
|
| `BLOSSOM_S3_ACCESS_KEY` | S3 access key ID | _optional_ |
|
||||||
|
| `BLOSSOM_S3_SECRET_KEY` | S3 secret access key | _optional_ |
|
||||||
| `NWC_URL` | Platform NWC URL used to generate BOLT11 invoices | _required for invoice generation_ |
|
| `NWC_URL` | Platform NWC URL used to generate BOLT11 invoices | _required for invoice generation_ |
|
||||||
| `ENCRYPTION_SECRET` | Nostr secret key (hex or nsec) used to encrypt tenant NWC URLs at rest | _required_ |
|
| `ENCRYPTION_SECRET` | Nostr secret key (hex or nsec) used to encrypt tenant NWC URLs at rest | _required_ |
|
||||||
| `STRIPE_SECRET_KEY` | Stripe API secret key used for billing API operations | _required_ |
|
| `STRIPE_SECRET_KEY` | Stripe API secret key used for billing API operations | _required_ |
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Infra is a service which listens for activity and synchronizes relay updates to
|
|||||||
Members:
|
Members:
|
||||||
|
|
||||||
- `api_url: String` - the URL of the zooid instance to be managed, from `ZOOID_API_URL`
|
- `api_url: String` - the URL of the zooid instance to be managed, from `ZOOID_API_URL`
|
||||||
|
- `blossom_s3: Option<BlossomS3Sync>` - shared Blossom S3 settings from `BLOSSOM_S3_*` when region, bucket, access key, and secret are all non-empty after trim
|
||||||
- `query: Query`
|
- `query: Query`
|
||||||
- `command: Command`
|
- `command: Command`
|
||||||
|
|
||||||
@@ -36,3 +37,4 @@ Members:
|
|||||||
- Otherwise, sends `PATCH /relay/:id` to update it.
|
- Otherwise, sends `PATCH /relay/:id` to update it.
|
||||||
- Includes `secret` only for relay creation (`POST`) so updates do not rotate relay identity.
|
- Includes `secret` only for relay creation (`POST`) so updates do not rotate relay identity.
|
||||||
- Passes relay configuration in the body including host, schema, inactive flag, info, policy, groups, management, blossom, livekit, push, and roles.
|
- Passes relay configuration in the body including host, schema, inactive flag, info, policy, groups, management, blossom, livekit, push, and roles.
|
||||||
|
- When `blossom_s3` is configured and the relay has blossom enabled, the blossom section includes `adapter: "s3"`, S3 fields from the environment, and `s3.key_prefix` set to the relay's `schema`. Otherwise blossom omits S3 (zooid defaults to local storage) or sends `{ "enabled": false }` when blossom is disabled.
|
||||||
|
|||||||
+94
-1
@@ -10,6 +10,47 @@ const RELAY_SYNC_RETRY_BASE_DELAY_SECS: u64 = 30;
|
|||||||
const RELAY_SYNC_RETRY_MAX_DELAY_SECS: u64 = 15 * 60;
|
const RELAY_SYNC_RETRY_MAX_DELAY_SECS: u64 = 15 * 60;
|
||||||
const RELAY_SYNC_RETRY_MAX_ATTEMPTS: usize = 6;
|
const RELAY_SYNC_RETRY_MAX_ATTEMPTS: usize = 6;
|
||||||
|
|
||||||
|
/// Blossom S3 settings from env; relay sync sets `key_prefix` to the relay schema.
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct BlossomS3Sync {
|
||||||
|
endpoint: String,
|
||||||
|
region: String,
|
||||||
|
bucket: String,
|
||||||
|
access_key: String,
|
||||||
|
secret_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlossomS3Sync {
|
||||||
|
fn from_env() -> Option<Self> {
|
||||||
|
let region = std::env::var("BLOSSOM_S3_REGION").unwrap_or_default();
|
||||||
|
let bucket = std::env::var("BLOSSOM_S3_BUCKET").unwrap_or_default();
|
||||||
|
let access_key = std::env::var("BLOSSOM_S3_ACCESS_KEY").unwrap_or_default();
|
||||||
|
let secret_key = std::env::var("BLOSSOM_S3_SECRET_KEY").unwrap_or_default();
|
||||||
|
|
||||||
|
let region = region.trim().to_string();
|
||||||
|
let bucket = bucket.trim().to_string();
|
||||||
|
let access_key = access_key.trim().to_string();
|
||||||
|
let secret_key = secret_key.trim().to_string();
|
||||||
|
|
||||||
|
if region.is_empty() || bucket.is_empty() || access_key.is_empty() || secret_key.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let endpoint = std::env::var("BLOSSOM_S3_ENDPOINT")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
Some(Self {
|
||||||
|
endpoint,
|
||||||
|
region,
|
||||||
|
bucket,
|
||||||
|
access_key,
|
||||||
|
secret_key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Infra {
|
pub struct Infra {
|
||||||
api_url: String,
|
api_url: String,
|
||||||
@@ -18,6 +59,7 @@ pub struct Infra {
|
|||||||
livekit_api_key: String,
|
livekit_api_key: String,
|
||||||
livekit_api_secret: String,
|
livekit_api_secret: String,
|
||||||
api_secret: String,
|
api_secret: String,
|
||||||
|
blossom_s3: Option<BlossomS3Sync>,
|
||||||
query: Query,
|
query: Query,
|
||||||
command: Command,
|
command: Command,
|
||||||
}
|
}
|
||||||
@@ -30,6 +72,7 @@ impl Infra {
|
|||||||
let livekit_api_key = std::env::var("LIVEKIT_API_KEY").unwrap_or_default();
|
let livekit_api_key = std::env::var("LIVEKIT_API_KEY").unwrap_or_default();
|
||||||
let livekit_api_secret = std::env::var("LIVEKIT_API_SECRET").unwrap_or_default();
|
let livekit_api_secret = std::env::var("LIVEKIT_API_SECRET").unwrap_or_default();
|
||||||
let api_secret = std::env::var("ZOOID_API_SECRET").unwrap_or_default();
|
let api_secret = std::env::var("ZOOID_API_SECRET").unwrap_or_default();
|
||||||
|
let blossom_s3 = BlossomS3Sync::from_env();
|
||||||
|
|
||||||
if api_url.trim().is_empty() {
|
if api_url.trim().is_empty() {
|
||||||
anyhow::bail!("missing ZOOID_API_URL");
|
anyhow::bail!("missing ZOOID_API_URL");
|
||||||
@@ -45,6 +88,7 @@ impl Infra {
|
|||||||
livekit_api_key,
|
livekit_api_key,
|
||||||
livekit_api_secret,
|
livekit_api_secret,
|
||||||
api_secret,
|
api_secret,
|
||||||
|
blossom_s3,
|
||||||
query,
|
query,
|
||||||
command,
|
command,
|
||||||
})
|
})
|
||||||
@@ -254,6 +298,7 @@ impl Infra {
|
|||||||
host,
|
host,
|
||||||
livekit,
|
livekit,
|
||||||
is_new.then(|| Keys::generate().secret_key().to_secret_hex()),
|
is_new.then(|| Keys::generate().secret_key().to_secret_hex()),
|
||||||
|
self.blossom_s3.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let url = format!("{}/relay/{}", base, relay.id);
|
let url = format!("{}/relay/{}", base, relay.id);
|
||||||
@@ -323,7 +368,10 @@ fn relay_sync_body(
|
|||||||
host: String,
|
host: String,
|
||||||
livekit: serde_json::Value,
|
livekit: serde_json::Value,
|
||||||
secret: Option<String>,
|
secret: Option<String>,
|
||||||
|
blossom_s3: Option<&BlossomS3Sync>,
|
||||||
) -> serde_json::Value {
|
) -> serde_json::Value {
|
||||||
|
let blossom = blossom_sync_json(relay, blossom_s3);
|
||||||
|
|
||||||
let mut body = serde_json::json!({
|
let mut body = serde_json::json!({
|
||||||
"host": host,
|
"host": host,
|
||||||
"schema": relay.schema,
|
"schema": relay.schema,
|
||||||
@@ -341,7 +389,7 @@ fn relay_sync_body(
|
|||||||
},
|
},
|
||||||
"groups": { "enabled": relay.groups_enabled == 1 },
|
"groups": { "enabled": relay.groups_enabled == 1 },
|
||||||
"management": { "enabled": relay.management_enabled == 1 },
|
"management": { "enabled": relay.management_enabled == 1 },
|
||||||
"blossom": { "enabled": relay.blossom_enabled == 1 },
|
"blossom": blossom,
|
||||||
"livekit": livekit,
|
"livekit": livekit,
|
||||||
"push": { "enabled": relay.push_enabled == 1 },
|
"push": { "enabled": relay.push_enabled == 1 },
|
||||||
"roles": {
|
"roles": {
|
||||||
@@ -357,6 +405,51 @@ fn relay_sync_body(
|
|||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blossom_sync_json(relay: &Relay, blossom_s3: Option<&BlossomS3Sync>) -> serde_json::Value {
|
||||||
|
let enabled = relay.blossom_enabled == 1;
|
||||||
|
if !enabled {
|
||||||
|
return serde_json::json!({ "enabled": false });
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(s3) = blossom_s3 else {
|
||||||
|
return serde_json::json!({ "enabled": true });
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut s3_obj = serde_json::Map::new();
|
||||||
|
if !s3.endpoint.trim().is_empty() {
|
||||||
|
s3_obj.insert(
|
||||||
|
"endpoint".to_string(),
|
||||||
|
serde_json::Value::String(s3.endpoint.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
s3_obj.insert(
|
||||||
|
"region".to_string(),
|
||||||
|
serde_json::Value::String(s3.region.clone()),
|
||||||
|
);
|
||||||
|
s3_obj.insert(
|
||||||
|
"bucket".to_string(),
|
||||||
|
serde_json::Value::String(s3.bucket.clone()),
|
||||||
|
);
|
||||||
|
s3_obj.insert(
|
||||||
|
"access_key".to_string(),
|
||||||
|
serde_json::Value::String(s3.access_key.clone()),
|
||||||
|
);
|
||||||
|
s3_obj.insert(
|
||||||
|
"secret_key".to_string(),
|
||||||
|
serde_json::Value::String(s3.secret_key.clone()),
|
||||||
|
);
|
||||||
|
s3_obj.insert(
|
||||||
|
"key_prefix".to_string(),
|
||||||
|
serde_json::Value::String(relay.schema.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
|
serde_json::json!({
|
||||||
|
"enabled": true,
|
||||||
|
"adapter": "s3",
|
||||||
|
"s3": serde_json::Value::Object(s3_obj),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn should_sync_relay_activity(activity_type: &str) -> bool {
|
fn should_sync_relay_activity(activity_type: &str) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
activity_type,
|
activity_type,
|
||||||
|
|||||||
Reference in New Issue
Block a user