///|
fn routing_int_map_from_body(body : Json?, key : String) -> Map[String, Int]? {
let values : Map[String, Int] = {}
guard body is Some(Object(obj)) else { return Some(values) }
guard obj.get(key) is Some(value) else { return Some(values) }
guard value is Object(entries) else { return None }
for provider_id, entry in entries {
guard !provider_id.trim().is_empty() else { return None }
match entry {
Number(number, ..) => values[provider_id] = number.trunc().to_int()
_ => return None
}
}
Some(values)
}
///|
fn routing_actor_and_authority_from_body(
body_obj : Map[String, Json],
) -> Result[
(@capability.PrincipalRefV1, @capability.AuthorityDecisionRefV1),
String,
] {
guard body_obj.get("actorPrincipal") is Some(actor_json) else {
return Err("missing_actor_principal")
}
guard body_obj.get("authorityDecision") is Some(authority_json) else {
return Err("missing_authority_decision")
}
let actor_result : Result[@capability.PrincipalRefV1, Error] = moon_result(() => {
@capability.decode_principal_ref_v1(actor_json)
})
guard actor_result is Ok(actor) else { return Err("invalid_actor_principal") }
let authority_result : Result[@capability.AuthorityDecisionRefV1, Error] = moon_result(() => {
@capability.decode_authority_decision_ref_v1(authority_json)
},
)
guard authority_result is Ok(authority) else {
return Err("invalid_authority_decision")
}
Ok((actor, authority))
}
///|
async fn ProxyService::handle_get_routing_policy(
self : ProxyService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard provider_app_from_request(r.path, body) is Some(app_type) else {
write_usage_bad_request(w, "missing_app")
return
}
write_usage_json(w, self.provider_router.routing_policy_state_json(app_type))
}
///|
async fn ProxyService::handle_configure_routing_policy(
self : ProxyService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard provider_app_from_request(r.path, body) is Some(app_type) else {
write_usage_bad_request(w, "missing_app")
return
}
guard proxy_string_request(r.path, body, "mode") is Some(mode_text) &&
@routing.parse_routing_mode(mode_text) is Some(mode) else {
write_usage_bad_request(w, "invalid_routing_mode")
return
}
guard routing_int_map_from_body(body, "weights") is Some(weights) else {
write_usage_bad_request(w, "invalid_routing_weights")
return
}
guard routing_int_map_from_body(body, "concurrencyLimits")
is Some(concurrency_limits) else {
write_usage_bad_request(w, "invalid_concurrency_limits")
return
}
let policy_id = proxy_string_request(r.path, body, "policyId").unwrap_or(
"\{app_type}.routing",
)
let minimum_shadow_decisions = proxy_int_request(
r.path,
body,
"minimumShadowDecisions",
).unwrap_or(20)
let minimum_shadow_window_ms = proxy_int_request(
r.path,
body,
"minimumShadowWindowMs",
)
.unwrap_or(300_000)
.to_int64()
let canary_traffic_basis_points = proxy_int_request(
r.path,
body,
"canaryTrafficBasisPoints",
).unwrap_or(500)
let rollback_error_rate_milli = proxy_int_request(
r.path,
body,
"rollbackErrorRateMilli",
).unwrap_or(100)
let rollback_p95_latency_ms = proxy_int_request(
r.path,
body,
"rollbackP95LatencyMs",
).unwrap_or(30_000)
let rollback_minimum_requests = proxy_int_request(
r.path,
body,
"rollbackMinimumRequests",
).unwrap_or(20)
match
self.provider_router.configure_routing_policy(
app_type~,
policy_id~,
mode~,
weights~,
concurrency_limits~,
minimum_shadow_decisions~,
minimum_shadow_window_ms~,
canary_traffic_basis_points~,
rollback_error_rate_milli~,
rollback_p95_latency_ms~,
rollback_minimum_requests~,
configured_at_ms=moongate_epoch_ms(),
) {
Err(error) => write_usage_bad_request(w, error)
Ok(policy) => {
if !self.persist_provider_store_or_error(w) {
return
}
write_usage_json(
w,
{
"status": Json::string("shadow-only"),
"policy": policy.to_json(),
"activationAllowed": Json::boolean(false),
}.to_json(),
)
}
}
}
///|
async fn ProxyService::handle_observe_routing_shadow(
self : ProxyService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard provider_app_from_request(r.path, body) is Some(app_type) else {
write_usage_bad_request(w, "missing_app")
return
}
guard self.provider_router.routing_policy_drafts.get(app_type) is Some(_) else {
write_usage_bad_request(w, "no_shadow_routing_policy")
return
}
self.provider_router.observe_shadow_routing(
app_type,
@async.now().to_int(),
session_key=proxy_string_request(r.path, body, "sessionKey"),
)
if !self.persist_provider_store_or_error(w) {
return
}
write_usage_json(w, self.provider_router.routing_policy_state_json(app_type))
}
///|
async fn ProxyService::handle_activate_routing_policy(
self : ProxyService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard provider_app_from_request(r.path, body) is Some(app_type) else {
write_usage_bad_request(w, "missing_app")
return
}
guard proxy_int_request(r.path, body, "expectedRevision")
is Some(expected_revision) else {
write_usage_bad_request(w, "missing_expected_revision")
return
}
guard body is Some(Object(body_obj)) else {
write_usage_bad_request(w, "missing_activation_body")
return
}
let actor_and_authority = routing_actor_and_authority_from_body(body_obj)
guard actor_and_authority is Ok((actor_principal, authority_decision)) else {
guard actor_and_authority is Err(error) else { return }
write_usage_bad_request(w, error)
return
}
let authority_checked_at = moongate_canonical_utc_now()
match
self.provider_router.activate_routing_policy(
app_type~,
expected_revision~,
actor_principal~,
authority_decision~,
authority_checked_at~,
receipt_id="routing-\{moongate_random_id()}",
recorded_at_ms=moongate_epoch_ms(),
) {
Err(error) => write_usage_bad_request(w, error)
Ok(receipt) => {
if !self.persist_provider_store_or_error(w) {
return
}
write_usage_json(w, receipt.to_json())
}
}
}
///|
async fn ProxyService::handle_rollback_routing_policy(
self : ProxyService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard provider_app_from_request(r.path, body) is Some(app_type) else {
write_usage_bad_request(w, "missing_app")
return
}
guard body is Some(Object(body_obj)) else {
write_usage_bad_request(w, "missing_rollback_body")
return
}
let actor_and_authority = routing_actor_and_authority_from_body(body_obj)
guard actor_and_authority is Ok((actor_principal, authority_decision)) else {
guard actor_and_authority is Err(error) else { return }
write_usage_bad_request(w, error)
return
}
let authority_checked_at = moongate_canonical_utc_now()
match
self.provider_router.rollback_routing_policy(
app_type~,
actor_principal~,
authority_decision~,
authority_checked_at~,
receipt_id="routing-\{moongate_random_id()}",
recorded_at_ms=moongate_epoch_ms(),
) {
Err(error) => write_usage_bad_request(w, error)
Ok(receipt) => {
if !self.persist_provider_store_or_error(w) {
return
}
write_usage_json(w, receipt.to_json())
}
}
}