mirror of
https://github.com/corda/corda.git
synced 2025-06-13 04:38:19 +00:00
Introduce FlowSession, startCounterFlow, Deprecate send/receive expec… (#1506)
* Introduce FlowSession, startCounterFlow, Deprecate send/receive expecting a Party * FlowSessionImpl * Change flow construtors to accept FlowSession * Add some docs and a small guide to porting * otherParty -> counterparty * minor kdoc fixes
This commit is contained in:
@ -53,15 +53,19 @@ abstract class FlowLogic<out T> {
|
||||
*/
|
||||
val serviceHub: ServiceHub get() = stateMachine.serviceHub
|
||||
|
||||
@Suspendable
|
||||
fun initiateFlow(party: Party): FlowSession = stateMachine.initiateFlow(party, flowUsedForSessions)
|
||||
|
||||
/**
|
||||
* Returns a [FlowContext] object describing the flow [otherParty] is using. With [FlowContext.flowVersion] it
|
||||
* Returns a [FlowInfo] object describing the flow [otherParty] is using. With [FlowInfo.flowVersion] it
|
||||
* provides the necessary information needed for the evolution of flows and enabling backwards compatibility.
|
||||
*
|
||||
* This method can be called before any send or receive has been done with [otherParty]. In such a case this will force
|
||||
* them to start their flow.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.getFlowInfo()", level = DeprecationLevel.WARNING)
|
||||
@Suspendable
|
||||
fun getFlowContext(otherParty: Party): FlowContext = stateMachine.getFlowContext(otherParty, flowUsedForSessions)
|
||||
fun getFlowInfo(otherParty: Party): FlowInfo = stateMachine.getFlowInfo(otherParty, flowUsedForSessions)
|
||||
|
||||
/**
|
||||
* Serializes and queues the given [payload] object for sending to the [otherParty]. Suspends until a response
|
||||
@ -76,6 +80,7 @@ abstract class FlowLogic<out T> {
|
||||
*
|
||||
* @returns an [UntrustworthyData] wrapper around the received object.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.sendAndReceive()", level = DeprecationLevel.WARNING)
|
||||
inline fun <reified R : Any> sendAndReceive(otherParty: Party, payload: Any): UntrustworthyData<R> {
|
||||
return sendAndReceive(R::class.java, otherParty, payload)
|
||||
}
|
||||
@ -91,6 +96,7 @@ abstract class FlowLogic<out T> {
|
||||
*
|
||||
* @returns an [UntrustworthyData] wrapper around the received object.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.sendAndReceive()", level = DeprecationLevel.WARNING)
|
||||
@Suspendable
|
||||
open fun <R : Any> sendAndReceive(receiveType: Class<R>, otherParty: Party, payload: Any): UntrustworthyData<R> {
|
||||
return stateMachine.sendAndReceive(receiveType, otherParty, payload, flowUsedForSessions)
|
||||
@ -105,8 +111,13 @@ abstract class FlowLogic<out T> {
|
||||
* oracle services. If one or more nodes in the service cluster go down mid-session, the message will be redelivered
|
||||
* to a different one, so there is no need to wait until the initial node comes back up to obtain a response.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.sendAndReceiveWithRetry()", level = DeprecationLevel.WARNING)
|
||||
internal inline fun <reified R : Any> sendAndReceiveWithRetry(otherParty: Party, payload: Any): UntrustworthyData<R> {
|
||||
return stateMachine.sendAndReceive(R::class.java, otherParty, payload, flowUsedForSessions, true)
|
||||
return stateMachine.sendAndReceive(R::class.java, otherParty, payload, flowUsedForSessions, retrySend = true)
|
||||
}
|
||||
@Suspendable
|
||||
internal fun <R : Any> FlowSession.sendAndReceiveWithRetry(receiveType: Class<R>, payload: Any): UntrustworthyData<R> {
|
||||
return stateMachine.sendAndReceive(receiveType, counterparty, payload, flowUsedForSessions, retrySend = true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,6 +127,7 @@ abstract class FlowLogic<out T> {
|
||||
* verified for consistency and that all expectations are satisfied, as a malicious peer may send you subtly
|
||||
* corrupted data in order to exploit your code.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.receive()", level = DeprecationLevel.WARNING)
|
||||
inline fun <reified R : Any> receive(otherParty: Party): UntrustworthyData<R> = receive(R::class.java, otherParty)
|
||||
|
||||
/**
|
||||
@ -127,6 +139,7 @@ abstract class FlowLogic<out T> {
|
||||
*
|
||||
* @returns an [UntrustworthyData] wrapper around the received object.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.receive()", level = DeprecationLevel.WARNING)
|
||||
@Suspendable
|
||||
open fun <R : Any> receive(receiveType: Class<R>, otherParty: Party): UntrustworthyData<R> {
|
||||
return stateMachine.receive(receiveType, otherParty, flowUsedForSessions)
|
||||
@ -139,6 +152,7 @@ abstract class FlowLogic<out T> {
|
||||
* is offline then message delivery will be retried until it comes back or until the message is older than the
|
||||
* network's event horizon time.
|
||||
*/
|
||||
@Deprecated("Use FlowSession.send()", level = DeprecationLevel.WARNING)
|
||||
@Suspendable
|
||||
open fun send(otherParty: Party, payload: Any) = stateMachine.send(otherParty, payload, flowUsedForSessions)
|
||||
|
||||
@ -294,7 +308,7 @@ abstract class FlowLogic<out T> {
|
||||
* Version and name of the CorDapp hosting the other side of the flow.
|
||||
*/
|
||||
@CordaSerializable
|
||||
data class FlowContext(
|
||||
data class FlowInfo(
|
||||
/**
|
||||
* The integer flow version the other side is using.
|
||||
* @see InitiatingFlow
|
||||
|
109
core/src/main/kotlin/net/corda/core/flows/FlowSession.kt
Normal file
109
core/src/main/kotlin/net/corda/core/flows/FlowSession.kt
Normal file
@ -0,0 +1,109 @@
|
||||
package net.corda.core.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
|
||||
/**
|
||||
* To port existing flows:
|
||||
*
|
||||
* Look for [Deprecated] usages of send/receive/sendAndReceive/getFlowInfo.
|
||||
*
|
||||
* If it's an InitiatingFlow:
|
||||
*
|
||||
* Look for the send/receive that kicks off the counter flow. Insert a
|
||||
*
|
||||
* val session = initiateFlow(party)
|
||||
*
|
||||
* and use this session afterwards for send/receives.
|
||||
* For example:
|
||||
* send(party, something)
|
||||
* will become
|
||||
* session.send(something)
|
||||
*
|
||||
* If it's an InitiatedBy flow:
|
||||
*
|
||||
* Change the constructor to take an initiatingSession: FlowSession instead of a counterparty: Party
|
||||
* Then look for usages of the deprecated functions and change them to use the FlowSession
|
||||
* For example:
|
||||
* send(counterparty, something)
|
||||
* will become
|
||||
* initiatingSession.send(something)
|
||||
*/
|
||||
abstract class FlowSession {
|
||||
abstract val counterparty: Party
|
||||
|
||||
/**
|
||||
* Returns a [FlowInfo] object describing the flow [counterparty] is using. With [FlowInfo.flowVersion] it
|
||||
* provides the necessary information needed for the evolution of flows and enabling backwards compatibility.
|
||||
*
|
||||
* This method can be called before any send or receive has been done with [counterparty]. In such a case this will force
|
||||
* them to start their flow.
|
||||
*/
|
||||
@Suspendable
|
||||
abstract fun getCounterpartyFlowInfo(): FlowInfo
|
||||
|
||||
/**
|
||||
* Serializes and queues the given [payload] object for sending to the [counterparty]. Suspends until a response
|
||||
* is received, which must be of the given [R] type.
|
||||
*
|
||||
* Remember that when receiving data from other parties the data should not be trusted until it's been thoroughly
|
||||
* verified for consistency and that all expectations are satisfied, as a malicious peer may send you subtly
|
||||
* corrupted data in order to exploit your code.
|
||||
*
|
||||
* Note that this function is not just a simple send+receive pair: it is more efficient and more correct to
|
||||
* use this when you expect to do a message swap than do use [send] and then [receive] in turn.
|
||||
*
|
||||
* @returns an [UntrustworthyData] wrapper around the received object.
|
||||
*/
|
||||
@Suspendable
|
||||
inline fun <reified R : Any> sendAndReceive(payload: Any): UntrustworthyData<R> {
|
||||
return sendAndReceive(R::class.java, payload)
|
||||
}
|
||||
/**
|
||||
* Serializes and queues the given [payload] object for sending to the [counterparty]. Suspends until a response
|
||||
* is received, which must be of the given [receiveType]. Remember that when receiving data from other parties the data
|
||||
* should not be trusted until it's been thoroughly verified for consistency and that all expectations are
|
||||
* satisfied, as a malicious peer may send you subtly corrupted data in order to exploit your code.
|
||||
*
|
||||
* Note that this function is not just a simple send+receive pair: it is more efficient and more correct to
|
||||
* use this when you expect to do a message swap than do use [send] and then [receive] in turn.
|
||||
*
|
||||
* @returns an [UntrustworthyData] wrapper around the received object.
|
||||
*/
|
||||
@Suspendable
|
||||
abstract fun <R : Any> sendAndReceive(receiveType: Class<R>, payload: Any): UntrustworthyData<R>
|
||||
|
||||
/**
|
||||
* Suspends until [counterparty] sends us a message of type [R].
|
||||
*
|
||||
* Remember that when receiving data from other parties the data should not be trusted until it's been thoroughly
|
||||
* verified for consistency and that all expectations are satisfied, as a malicious peer may send you subtly
|
||||
* corrupted data in order to exploit your code.
|
||||
*/
|
||||
@Suspendable
|
||||
inline fun <reified R : Any> receive(): UntrustworthyData<R> {
|
||||
return receive(R::class.java)
|
||||
}
|
||||
/**
|
||||
* Suspends until [counterparty] sends us a message of type [receiveType].
|
||||
*
|
||||
* Remember that when receiving data from other parties the data should not be trusted until it's been thoroughly
|
||||
* verified for consistency and that all expectations are satisfied, as a malicious peer may send you subtly
|
||||
* corrupted data in order to exploit your code.
|
||||
*
|
||||
* @returns an [UntrustworthyData] wrapper around the received object.
|
||||
*/
|
||||
@Suspendable
|
||||
abstract fun <R : Any> receive(receiveType: Class<R>): UntrustworthyData<R>
|
||||
|
||||
/**
|
||||
* Queues the given [payload] for sending to the [counterparty] and continues without suspending.
|
||||
*
|
||||
* Note that the other party may receive the message at some arbitrary later point or not at all: if [counterparty]
|
||||
* is offline then message delivery will be retried until it comes back or until the message is older than the
|
||||
* network's event horizon time.
|
||||
*/
|
||||
@Suspendable
|
||||
abstract fun send(payload: Any)
|
||||
}
|
@ -13,7 +13,10 @@ import org.slf4j.Logger
|
||||
/** This is an internal interface that is implemented by code in the node module. You should look at [FlowLogic]. */
|
||||
interface FlowStateMachine<R> {
|
||||
@Suspendable
|
||||
fun getFlowContext(otherParty: Party, sessionFlow: FlowLogic<*>): FlowContext
|
||||
fun getFlowInfo(otherParty: Party, sessionFlow: FlowLogic<*>): FlowInfo
|
||||
|
||||
@Suspendable
|
||||
fun initiateFlow(otherParty: Party, sessionFlow: FlowLogic<*>): FlowSession
|
||||
|
||||
@Suspendable
|
||||
fun <T : Any> sendAndReceive(receiveType: Class<T>,
|
||||
|
@ -147,7 +147,7 @@ class AttachmentSerializationTest {
|
||||
private fun launchFlow(clientLogic: ClientLogic, rounds: Int, sendData: Boolean = false) {
|
||||
server.internals.internalRegisterFlowFactory(
|
||||
ClientLogic::class.java,
|
||||
InitiatedFlowFactory.Core { ServerLogic(it, sendData) },
|
||||
InitiatedFlowFactory.Core { ServerLogic(it.counterparty, sendData) },
|
||||
ServerLogic::class.java,
|
||||
track = false)
|
||||
client.services.startFlow(clientLogic)
|
||||
|
Reference in New Issue
Block a user