Skip to content

Commit

Permalink
Make Receiver state machine generic
Browse files Browse the repository at this point in the history
This allows us to share common functions with every state in preparation
to handle errors with data from the SessionContext.
  • Loading branch information
DanGould committed Jan 9, 2025
1 parent eaf2398 commit 486ccfe
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 181 deletions.
18 changes: 10 additions & 8 deletions payjoin-cli/src/app/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use bitcoincore_rpc::RpcApi;
use payjoin::bitcoin::consensus::encode::serialize_hex;
use payjoin::bitcoin::psbt::Psbt;
use payjoin::bitcoin::{Amount, FeeRate};
use payjoin::receive::v2::Receiver;
use payjoin::receive::v2::{
InitialState, PayjoinProposal, ProvisionalProposal, Receiver, UncheckedProposal, WantsInputs,
};
use payjoin::send::v2::{Sender, SenderBuilder};
use payjoin::{bitcoin, Error, Uri};
use tokio::signal;
Expand Down Expand Up @@ -113,7 +115,7 @@ impl App {
#[allow(clippy::incompatible_msrv)]
async fn spawn_payjoin_receiver(
&self,
mut session: Receiver,
mut session: Receiver<InitialState>,
amount: Option<Amount>,
) -> Result<()> {
println!("Receive session established");
Expand Down Expand Up @@ -236,8 +238,8 @@ impl App {

async fn long_poll_fallback(
&self,
session: &mut payjoin::receive::v2::Receiver,
) -> Result<payjoin::receive::v2::UncheckedProposal> {
session: &mut Receiver<InitialState>,
) -> Result<Receiver<UncheckedProposal>> {
loop {
let (req, context) = session.extract_req()?;
println!("Polling receive request...");
Expand All @@ -254,8 +256,8 @@ impl App {

fn process_v2_proposal(
&self,
proposal: payjoin::receive::v2::UncheckedProposal,
) -> Result<payjoin::receive::v2::PayjoinProposal, Error> {
proposal: Receiver<UncheckedProposal>,
) -> Result<Receiver<PayjoinProposal>, Error> {
let bitcoind = self.bitcoind().map_err(|e| Error::Server(e.into()))?;

// in a payment processor where the sender could go offline, this is where you schedule to broadcast the original_tx
Expand Down Expand Up @@ -334,9 +336,9 @@ impl App {
}

fn try_contributing_inputs(
payjoin: payjoin::receive::v2::WantsInputs,
payjoin: Receiver<WantsInputs>,
bitcoind: &bitcoincore_rpc::Client,
) -> Result<payjoin::receive::v2::ProvisionalProposal> {
) -> Result<Receiver<ProvisionalProposal>> {
let candidate_inputs = bitcoind
.list_unspent(None, None, None, None, None)
.context("Failed to list unspent from bitcoind")?
Expand Down
9 changes: 5 additions & 4 deletions payjoin-cli/src/db/v2.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use bitcoincore_rpc::jsonrpc::serde_json;
use payjoin::receive::v2::Receiver;
use payjoin::receive::v2::{InitialState, Receiver};
use payjoin::send::v2::Sender;
use sled::{IVec, Tree};
use url::Url;

use super::*;

impl Database {
pub(crate) fn insert_recv_session(&self, session: Receiver) -> Result<()> {
pub(crate) fn insert_recv_session(&self, session: Receiver<InitialState>) -> Result<()> {
let recv_tree = self.0.open_tree("recv_sessions")?;
let key = &session.id();
let value = serde_json::to_string(&session).map_err(Error::Serialize)?;
Expand All @@ -16,12 +16,13 @@ impl Database {
Ok(())
}

pub(crate) fn get_recv_sessions(&self) -> Result<Vec<Receiver>> {
pub(crate) fn get_recv_sessions(&self) -> Result<Vec<Receiver<InitialState>>> {
let recv_tree = self.0.open_tree("recv_sessions")?;
let mut sessions = Vec::new();
for item in recv_tree.iter() {
let (_, value) = item?;
let session: Receiver = serde_json::from_slice(&value).map_err(Error::Deserialize)?;
let session: Receiver<InitialState> =
serde_json::from_slice(&value).map_err(Error::Deserialize)?;
sessions.push(session);
}
Ok(sessions)
Expand Down
11 changes: 11 additions & 0 deletions payjoin/src/receive/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ pub enum Error {
Server(Box<dyn error::Error>),
}

impl Error {
pub fn to_json(&self) -> String {
match self {
Self::BadRequest(e) => e.to_string(),
Self::Server(_) =>
"{{ \"errorCode\": \"server-error\", \"message\": \"Internal server error\" }}"
.to_string(),
}
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
Expand Down
Loading

0 comments on commit 486ccfe

Please sign in to comment.