流媒体推流怎么做
在Corda中,Flows可以做很多事情,而不是提出在组织之间进行记录的新交易。 尽管说他们可以做任何事情可能影响深远(不过这很容易上手)。 我真正要说的是,流是节点的入口点。 Corda提供了一系列通过RPC与节点交互的功能。 当前,这些内容涵盖了更直接的用例,例如查询保管库,但是所提供的内容受到限制。 流程涵盖了需要触发的任何非标准逻辑。 因此,如果要从客户端可以触发或使用的Corda节点公开API,那么此文章适合您。
在本文中,我将探索使用流作为节点的入口点。 提出新交易的流程将在其他许多教程中显示,并且已从本文中排除。 众人瞩目的焦点将仅仅放在提供不同功能的流上。
理论
如引言中所述,我想重申一下,从Corda节点公开终结点或API的唯一方法是通过流。 现有的RPC端点将处理标准功能。 将来可能会改变,增加对自定义RPC端点的支持。 但是,到目前为止(Corda 4),流是在节点内运行非标准逻辑的唯一方法。
我认为,通过流公开节点的功能与为Web服务器编写HTTP端点非常相似。 您必须定义可访问的内容。 客户端无法请求访问Web服务器内部的任何内部代码。 如果没有端点,则会发回错误。 科尔达也是如此。 这样,就可以更直接地推断出客户端在与节点进行交互时可以做什么或不能做什么。
关于实现,最简单的入门方法是向您展示一个示例:
@StartableByRPC class StupidSimpleQueryFlow( private val externalId: String) : FlowLogic<MessageState>() {
// does not need to be suspendable?
override fun call(): MessageState {
return serviceHub.vaultService.queryBy<MessageState>(
QueryCriteria.LinearStateQueryCriteria(
externalId = listOf(externalId)
)
).states.single().state.data
} }
如果您了解自己的知识,那么您将意识到可以通过RPC做到这一点。 我选择了这个示例,以熟悉一些东西开始。 您可能已经在自己的流程中进行了类似的查询。 尽管它们很有可能是更广泛过程的一部分。
与大多数流程相比,这里有几件事需要注意:
- 没有
@InitiatingFlow
批注 - 没有
@Suspendable
注解 - 没有匹配的响应者流程
他们为什么失踪? 好吧,它们不是必需的。 想一想。 每个点都与与另一个节点的通信相关,这没有发生。 该流程开始,执行查询并返回检索到的数据。 让我对此进行扩展:
-
@InitiatingFlow
允许流创建新会话以与其他节点进行通信。 由于不需要交互,因此无需创建会话,因此可以删除注释。 - 在挂起的函数上需要
@Suspendable
。 允许流创建需要再次唤醒时加载的检查点 。 流暂停的最常见位置是在与另一个节点通信期间。 在这种情况下,可以删除注释,因为流程永远不需要暂停。 - 响应者流在交易对手节点上运行,并在您
send
它们send
数据时与您的流进行交互。 同样,没有通信,因此不需要其他节点安装与上述流配对的流。
大多数不与其他节点交互的流将遵循这种结构(某些流仍可以根据您的操作而挂起)。
然后可以从外部客户端访问上面定义的流程:
proxy.startFlow(::StupidSimpleQueryFlow, "asdas" ).returnValue.get()
例子
以下是一些您可以编写的流程示例以及为什么使用它们。
从服务中获取价值
@StartableByRPC class GetMeSomeValueFromAService : FlowLogic<Long>() {
override fun call(): Long {
return .java).counter serviceHub.cordaService(IncrementingService:: class .java).counter
} } @CordaService class IncrementingService(serviceHub: AppServiceHub) : SingletonSerializeAsToken() {
var counter: Long = 0
init {
timer(period = TimeUnit.SECONDS.toMillis( 1 )) {
counter += 1
}
} }
如果您有一项服务,该服务存储了一些对外部客户端有用的信息,则需要一种方法来检索它。
在节点内部调用代码以减少代码重复
@StartableByRPC class ExecuteSomeInternalNodeLogicYouDontWantToDuplicateFlow( private val recipient: Party) :
FlowLogic<List<MessageState>>() {
override fun call(): List<MessageState> {
return serviceHub.cordaService(MessageRepository:: class .java)
.findAllMessagesByRecipient(recipient)
} } @CordaService class MessageRepository( private val serviceHub: AppServiceHub) : SingletonSerializeAsToken() {
fun findAllMessagesByRecipient(recipient: Party): List<MessageState> {
return serviceHub.vaultService.queryBy<MessageState>(
QueryCriteria.VaultCustomQueryCriteria(
builder { MessageSchema.PersistentMessage::recipient.equal(recipient.name.toString()) }
)
).states.map { it.state.data }
} }
有用的可重用代码段可以提取到单独的类中。 更具体地说,对于Corda,您可以在流程或服务中放置逻辑。
要从客户端执行流或服务中的代码:
- 流程内部 –只需从客户端调用流程
- 在服务内部 –添加委派给服务的新流程
您可以在客户端中实现上面的查询,但是如果您在节点内也使用相同的查询,则将有两个版本。
执行无法通过RPC完成的逻辑
@StartableByRPC class DoSomethingComplicatedThatYouCantDoViaRpc( private val recipient: Party) :
FlowLogic<List<MessageSchema.PersistentMessage>>() {
override fun call(): List<MessageSchema.PersistentMessage> {
return serviceHub.withEntityManager {
createQuery(
"SELECT m FROM $TABLE_NAME m WHERE m.recipient = ?1" ,
MessageSchema.PersistentMessage:: class .java
).setParameter(
1 ,
recipient.name.toString()
).resultList
}
}
private companion object {
val TABLE_NAME = MessageSchema.PersistentMessage:: class .jvmName
} }
如前所述,通过RPC可以执行的操作受到限制。 上面的代码就是一个例子。 它访问EntityManager
,它可以执行比Vault允许的级别低的查询。
结论
这篇文章的简短结论。 流是节点中可以运行完全自定义逻辑的唯一入口点。 Corda提供了几种与节点交互的API,但是这些API提供的功能有限。 要执行任何类型的逻辑(节点可以运行),您需要具有允许进入该节点并为您按下按钮的流程。
翻译自: https://www.javacodegeeks.com/2019/08/flows-can-do-anything.html
流媒体推流怎么做