Implement replay-safe authorized public HTTP API
This commit is contained in:
parent
791e00f4c0
commit
4c93c25692
2 changed files with 3940 additions and 345 deletions
|
|
@ -48,6 +48,51 @@ pub struct MutationOutcome {
|
|||
pub response: Value,
|
||||
}
|
||||
|
||||
pub async fn observe_mutation(
|
||||
pool: &PgPool,
|
||||
scope: MutationScope<'_>,
|
||||
kind: &str,
|
||||
eligibility_claim: &[u8],
|
||||
request_fingerprint: RequestFingerprint,
|
||||
) -> Result<Option<MutationOutcome>, DurableError> {
|
||||
let existing = sqlx::query_as::<_, (String, Vec<u8>, Vec<u8>, String, Value)>(
|
||||
"SELECT kind, eligibility_claim, request_fingerprint, response_status, response_body
|
||||
FROM mutation_records
|
||||
WHERE scope_subject = $1
|
||||
AND scope_operation = $2
|
||||
AND operation_key = $3",
|
||||
)
|
||||
.bind(scope.subject.as_str())
|
||||
.bind(scope.operation)
|
||||
.bind(scope.key)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
existing
|
||||
.map(
|
||||
|(
|
||||
stored_kind,
|
||||
stored_eligibility_claim,
|
||||
stored_request_fingerprint,
|
||||
response_status,
|
||||
response_body,
|
||||
)| {
|
||||
observe_existing(
|
||||
kind,
|
||||
eligibility_claim,
|
||||
request_fingerprint.as_bytes(),
|
||||
StoredRecord {
|
||||
kind: stored_kind,
|
||||
eligibility_claim: stored_eligibility_claim,
|
||||
request_fingerprint: stored_request_fingerprint,
|
||||
response_status,
|
||||
response_body,
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
.transpose()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct StoredRecord {
|
||||
kind: String,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ pub use cursor::{CursorCodec, KeysetCursor, KeysetPosition, first_page_cursor, n
|
|||
pub use error::DurableError;
|
||||
pub use ledger::{
|
||||
MutationDisposition, MutationOutcome, MutationStatus, execute_mutation, execute_mutation_in_tx,
|
||||
observe_mutation,
|
||||
};
|
||||
pub use migrate::{migrate, migrator};
|
||||
pub use outbox::{
|
||||
|
|
|
|||
Loading…
Reference in a new issue