Skip to content

Commit e8e4336

Browse files
authored
Merge pull request #177 from libp2p/0.7.0
Release 0.7.0 * Add the ability to pre-handle any inbound or outbound stream (#170) * Check the full causal chain when handling exceptions (#173) * Update gossip scoring APIs: allow topic scoring params to be updated after startup (#175)
2 parents e7acb51 + 6e4917c commit e8e4336

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1898
-737
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ Builds are published to JCenter. Maven Central mirrors JCenter, but updates can
6969
jcenter()
7070
}
7171
72-
implementation 'io.libp2p:jvm-libp2p-minimal:0.6.4-RELEASE'
72+
implementation 'io.libp2p:jvm-libp2p-minimal:0.7.0-RELEASE'
7373
```
7474
### Using Maven
7575
```
7676
<dependency>
7777
<groupId>io.libp2p</groupId>
7878
<artifactId>jvm-libp2p-minimal</artifactId>
79-
<version>0.6.4-RELEASE</version>
79+
<version>0.7.0-RELEASE</version>
8080
<type>pom</type>
8181
</dependency>
8282
```

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import java.nio.file.Paths
1313
// ./gradlew bintrayUpload -PbintrayUser=<user> -PbintrayApiKey=<api-key>
1414

1515
group = "io.libp2p"
16-
version = "0.6.4-RELEASE"
16+
version = "0.7.0-RELEASE"
1717
description = "a minimal implementation of libp2p for the jvm"
1818

1919
plugins {

src/main/java/io/libp2p/core/dsl/HostBuilder.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import io.libp2p.core.Host;
44
import io.libp2p.core.crypto.PrivKey;
55
import io.libp2p.core.multistream.ProtocolBinding;
6-
import io.libp2p.core.mux.StreamMuxer;
6+
import io.libp2p.core.mux.StreamMuxerProtocol;
77
import io.libp2p.core.security.SecureChannel;
88
import io.libp2p.core.transport.Transport;
99
import io.libp2p.transport.ConnectionUpgrader;
@@ -48,7 +48,7 @@ public final HostBuilder secureChannel(
4848

4949
@SafeVarargs
5050
public final HostBuilder muxer(
51-
Supplier<StreamMuxer>... muxers) {
51+
Supplier<StreamMuxerProtocol>... muxers) {
5252
muxers_.addAll(Arrays.asList(muxers));
5353
return this;
5454
}
@@ -79,7 +79,7 @@ public Host build() {
7979
b.getSecureChannels().add(sc::apply)
8080
);
8181
muxers_.forEach(m ->
82-
b.getMuxers().add(m::get)
82+
b.getMuxers().add(m.get())
8383
);
8484
b.getProtocols().addAll(protocols_);
8585
listenAddresses_.forEach(a ->
@@ -92,7 +92,7 @@ public Host build() {
9292
private DefaultMode defaultMode_;
9393
private List<Function<ConnectionUpgrader, Transport>> transports_ = new ArrayList<>();
9494
private List<Function<PrivKey, SecureChannel>> secureChannels_ = new ArrayList<>();
95-
private List<Supplier<StreamMuxer>> muxers_ = new ArrayList<>();
95+
private List<Supplier<StreamMuxerProtocol>> muxers_ = new ArrayList<>();
9696
private List<ProtocolBinding<?>> protocols_ = new ArrayList<>();
9797
private List<String> listenAddresses_ = new ArrayList<>();
9898
}

src/main/kotlin/io/libp2p/core/ConnectionHandler.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import io.libp2p.etc.BroadcastConnectionHandler
55
/**
66
* The same as [P2PChannelHandler] with the [Connection] specialized [P2PChannel]
77
*/
8-
interface ConnectionHandler {
8+
fun interface ConnectionHandler {
99

1010
fun handleConnection(conn: Connection)
1111

@@ -19,9 +19,6 @@ interface ConnectionHandler {
1919
}
2020
fun createBroadcast(handlers: List<ConnectionHandler> = listOf()): Broadcast =
2121
BroadcastConnectionHandler().also { it += handlers }
22-
23-
fun createStreamHandlerInitializer(streamHandler: StreamHandler<*>) =
24-
create { it.muxerSession().inboundStreamHandler = streamHandler }
2522
}
2623

2724
interface Broadcast : ConnectionHandler, MutableList<ConnectionHandler>

src/main/kotlin/io/libp2p/core/Host.kt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ interface Host {
4141
* List of all streams opened at the moment across all the [Connection]s
4242
* Please note that this list is updated asynchronously so the streams upon receiving
4343
* of this list can be already closed or not yet completely initialized
44-
* To be synchronously notified on stream creation use [addStreamHandler] and
44+
* To be synchronously notified on stream creation use [addStreamVisitor] and
4545
* use [Stream.closeFuture] to be synchronously notified on stream close
4646
*/
4747
val streams: List<Stream>
@@ -59,17 +59,20 @@ interface Host {
5959
fun stop(): CompletableFuture<Void>
6060

6161
/**
62-
* Adds a handler which is notified when a new [Stream] is created
63-
* Note that this is just a hook to be informed on a stream creation
64-
* and no actual [Stream.nettyChannel] initialization should happen here.
65-
* Refer to [addProtocolHandler] to setup a specific protocol handler
62+
* Add the [ChannelVisitor] which would be invoked prior to any protocol [StreamHandler]s on any
63+
* created inbound or outbound [Stream]
64+
* The [streamVisitor] is free to setup any handlers on a [Stream] however those handlers
65+
* should be careful to propagate any events up/down the Netty pipeline and not modify
66+
* [ByteBuf]s to keep protocol [StreamHandler]s functioning as expected
6667
*/
67-
fun addStreamHandler(handler: StreamHandler<*>)
68+
fun addStreamVisitor(streamVisitor: ChannelVisitor<Stream>)
6869

6970
/**
70-
* Removes the handler added with [addStreamHandler]
71+
* Removes the visitor added with [addStreamVisitor]
72+
* Please note that removing a visitor doesn't affect any Netty handlers installed by the visitor
73+
* on any streams created before
7174
*/
72-
fun removeStreamHandler(handler: StreamHandler<*>)
75+
fun removeStreamVisitor(streamVisitor: ChannelVisitor<Stream>)
7376

7477
/**
7578
* Adds a new supported protocol 'on the fly'
Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,39 @@
11
package io.libp2p.core
22

3+
import io.libp2p.etc.BroadcastChannelVisitor
34
import java.util.concurrent.CompletableFuture
45

56
/**
67
* The central entry point for every protocol which is responsible for initializing [P2PChannel]
78
*/
8-
interface P2PChannelHandler<out TController> {
9+
fun interface P2PChannelHandler<TController> {
910

1011
/**
1112
* Should initialize the underlying Netty [io.netty.channel.Channel] **synchronously**
1213
* and **on the calling thread**
1314
* Returns the [Future] which is completed with the protocol [TController]
1415
* when all necessary protocol negotiations are done.
1516
*/
16-
fun initChannel(ch: P2PChannel): CompletableFuture<out TController>
17+
fun initChannel(ch: P2PChannel): CompletableFuture<TController>
1718

18-
fun toStreamHandler(): StreamHandler<TController> = object : StreamHandler<TController> {
19-
override fun handleStream(stream: Stream): CompletableFuture<out TController> {
20-
return initChannel(stream)
21-
}
19+
@JvmDefault
20+
fun toStreamHandler(): StreamHandler<TController> = StreamHandler { stream -> initChannel(stream) }
21+
}
22+
23+
fun interface ChannelVisitor<TChannel : P2PChannel> {
24+
25+
fun visit(channel: TChannel)
26+
27+
@JvmDefault
28+
fun toChannelHandler(): P2PChannelHandler<Unit> = P2PChannelHandler {
29+
visit(it as TChannel)
30+
CompletableFuture.completedFuture(Unit)
31+
}
32+
33+
interface Broadcast<TChannel : P2PChannel> : ChannelVisitor<TChannel>, MutableList<ChannelVisitor<TChannel>>
34+
35+
companion object {
36+
fun <TChannel : P2PChannel> createBroadcast(vararg handlers: ChannelVisitor<TChannel>) =
37+
BroadcastChannelVisitor<TChannel>().also { it += handlers }
2238
}
2339
}
Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.libp2p.core
22

3-
import io.libp2p.etc.BroadcastStreamHandler
43
import java.util.concurrent.CompletableFuture
54

65
/**
@@ -22,28 +21,7 @@ data class StreamPromise<T>(
2221
/**
2322
* The same as [P2PChannelHandler] with the [Stream] specialized [P2PChannel]
2423
*/
25-
interface StreamHandler<out TController> {
24+
fun interface StreamHandler<TController> {
2625

27-
fun handleStream(stream: Stream): CompletableFuture<out TController>
28-
29-
companion object {
30-
31-
fun create(fn: (Stream) -> Unit) = object : StreamHandler<Unit> {
32-
override fun handleStream(stream: Stream): CompletableFuture<out Unit> {
33-
fn(stream)
34-
return CompletableFuture.completedFuture(Unit)
35-
}
36-
}
37-
38-
fun <T> create(channelHandler: P2PChannelHandler<T>) = object : StreamHandler<T> {
39-
override fun handleStream(stream: Stream): CompletableFuture<out T> {
40-
return channelHandler.initChannel(stream)
41-
}
42-
}
43-
44-
fun createBroadcast(vararg handlers: StreamHandler<*>) =
45-
BroadcastStreamHandler().also { it += handlers }
46-
}
47-
48-
interface Broadcast : StreamHandler<Any>, MutableList<StreamHandler<*>>
26+
fun handleStream(stream: Stream): CompletableFuture<TController>
4927
}

src/main/kotlin/io/libp2p/core/dsl/Builders.kt

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,29 @@ package io.libp2p.core.dsl
22

33
import identify.pb.IdentifyOuterClass
44
import io.libp2p.core.AddressBook
5+
import io.libp2p.core.ChannelVisitor
6+
import io.libp2p.core.Connection
57
import io.libp2p.core.ConnectionHandler
68
import io.libp2p.core.Host
7-
import io.libp2p.core.StreamHandler
9+
import io.libp2p.core.P2PChannel
10+
import io.libp2p.core.Stream
811
import io.libp2p.core.crypto.KEY_TYPE
912
import io.libp2p.core.crypto.PrivKey
1013
import io.libp2p.core.crypto.generateKeyPair
1114
import io.libp2p.core.multiformats.Multiaddr
12-
import io.libp2p.core.multistream.Multistream
15+
import io.libp2p.core.multistream.MultistreamProtocol
16+
import io.libp2p.core.multistream.MultistreamProtocolDebug
17+
import io.libp2p.core.multistream.MultistreamProtocolV1
1318
import io.libp2p.core.multistream.ProtocolBinding
1419
import io.libp2p.core.mux.StreamMuxer
1520
import io.libp2p.core.mux.StreamMuxerDebug
21+
import io.libp2p.core.mux.StreamMuxerProtocol
1622
import io.libp2p.core.security.SecureChannel
1723
import io.libp2p.core.transport.Transport
1824
import io.libp2p.etc.types.lazyVar
1925
import io.libp2p.etc.types.toProtobuf
2026
import io.libp2p.host.HostImpl
2127
import io.libp2p.host.MemoryAddressBook
22-
import io.libp2p.mux.mplex.MplexStreamMuxer
2328
import io.libp2p.network.NetworkImpl
2429
import io.libp2p.protocol.IdentifyBinding
2530
import io.libp2p.security.secio.SecIoSecureChannel
@@ -31,8 +36,6 @@ import io.netty.handler.logging.LoggingHandler
3136

3237
typealias TransportCtor = (ConnectionUpgrader) -> Transport
3338
typealias SecureChannelCtor = (PrivKey) -> SecureChannel
34-
typealias StreamMuxerCtor = () -> StreamMuxer
35-
typealias ProtocolCtor = () -> ProtocolBinding<*>
3639
typealias IdentityFactory = () -> PrivKey
3740

3841
class HostConfigurationException(message: String) : RuntimeException(message)
@@ -58,6 +61,10 @@ open class Builder {
5861
protected open val connectionHandlers = ConnectionHandlerBuilder()
5962
protected open val network = NetworkConfigBuilder()
6063
protected open val debug = DebugBuilder()
64+
var multistreamProtocol: MultistreamProtocol = MultistreamProtocolV1
65+
var secureMultistreamProtocol: MultistreamProtocol by lazyVar { multistreamProtocol }
66+
var muxerMultistreamProtocol: MultistreamProtocol by lazyVar { multistreamProtocol }
67+
var streamMultistreamProtocol: MultistreamProtocol by lazyVar { multistreamProtocol }
6168

6269
/**
6370
* Sets an identity for this host. If unset, libp2p will default to a random identity.
@@ -125,23 +132,35 @@ open class Builder {
125132
if (identity.factory == null) identity.random()
126133
if (transports.values.isEmpty()) transports { add(::TcpTransport) }
127134
if (secureChannels.values.isEmpty()) secureChannels { add(::SecIoSecureChannel) }
128-
if (muxers.values.isEmpty()) muxers { add(::MplexStreamMuxer) }
135+
if (muxers.values.isEmpty()) muxers { add(StreamMuxerProtocol.Mplex) }
129136
}
130137

131-
val privKey = identity.factory!!()
138+
if (debug.beforeSecureHandler.handlers.isNotEmpty()) {
139+
(secureMultistreamProtocol as? MultistreamProtocolDebug)?.also {
140+
val broadcast = ChannelVisitor.createBroadcast(*debug.beforeSecureHandler.handlers.toTypedArray())
141+
secureMultistreamProtocol = it.copyWithHandlers(preHandler = broadcast.toChannelHandler())
142+
} ?: throw IllegalStateException("beforeSecureHandler can't be installed as MultistreamProtocol doesn't support debugging interface: ${secureMultistreamProtocol.javaClass}")
143+
}
132144

133-
val secureChannels = secureChannels.values.map { it(privKey) }
134-
val muxers = muxers.values.map { it() }
145+
if (debug.afterSecureHandler.handlers.isNotEmpty()) {
146+
(muxerMultistreamProtocol as? MultistreamProtocolDebug)?.also {
147+
val broadcast = ChannelVisitor.createBroadcast(*debug.afterSecureHandler.handlers.toTypedArray())
148+
muxerMultistreamProtocol = it.copyWithHandlers(preHandler = broadcast.toChannelHandler())
149+
} ?: throw IllegalStateException("afterSecureHandler can't be installed as MultistreamProtocol doesn't support debugging interface: ${muxerMultistreamProtocol.javaClass}")
150+
}
135151

136-
muxers.mapNotNull { it as? StreamMuxerDebug }.forEach { it.muxFramesDebugHandler = debug.muxFramesHandler.handler }
152+
val streamVisitors = ChannelVisitor.createBroadcast<Stream>()
153+
(streamMultistreamProtocol as? MultistreamProtocolDebug)?.also {
154+
val broadcastPre =
155+
ChannelVisitor.createBroadcast(*(debug.streamPreHandler.handlers + (streamVisitors as ChannelVisitor<Stream>)).toTypedArray())
156+
val broadcast = ChannelVisitor.createBroadcast(*debug.streamHandler.handlers.toTypedArray())
157+
streamMultistreamProtocol =
158+
it.copyWithHandlers(broadcastPre.toChannelHandler(), broadcast.toChannelHandler())
159+
} ?: throw IllegalStateException("streamPreHandler or streamHandler can't be installed as MultistreamProtocol doesn't support debugging interface: ${streamMultistreamProtocol.javaClass}")
137160

138-
val upgrader = ConnectionUpgrader(secureChannels, muxers).apply {
139-
beforeSecureHandler = debug.beforeSecureHandler.handler
140-
afterSecureHandler = debug.afterSecureHandler.handler
141-
}
161+
val privKey = identity.factory!!()
142162

143-
val transports = transports.values.map { it(upgrader) }
144-
val addressBook = addressBook.impl
163+
val secureChannels = secureChannels.values.map { it(privKey) }
145164

146165
protocols.values.mapNotNull { (it as? IdentifyBinding) }.map { it.protocol }.find { it.idMessage == null }?.apply {
147166
// initializing Identify with appropriate values
@@ -156,16 +175,23 @@ open class Builder {
156175
}
157176
}
158177

159-
val protocolsMultistream: Multistream<Any> = Multistream.create(protocols.values)
160-
val broadcastStreamHandler = StreamHandler.createBroadcast()
161-
val allStreamHandlers = StreamHandler.createBroadcast(
162-
protocolsMultistream.toStreamHandler(), broadcastStreamHandler
163-
)
178+
val muxers = muxers.map { it.createMuxer(streamMultistreamProtocol, protocols.values) }
179+
180+
if (debug.muxFramesHandler.handlers.isNotEmpty()) {
181+
val broadcast = ChannelVisitor.createBroadcast(*debug.muxFramesHandler.handlers.toTypedArray())
182+
muxers.mapNotNull { it as? StreamMuxerDebug }.forEach {
183+
it.muxFramesDebugHandler = broadcast
184+
}
185+
}
186+
187+
val upgrader = ConnectionUpgrader(secureMultistreamProtocol, secureChannels, muxerMultistreamProtocol, muxers)
188+
189+
val transports = transports.values.map { it(upgrader) }
190+
val addressBook = addressBook.impl
164191

165192
val connHandlerProtocols = protocols.values.mapNotNull { it as? ConnectionHandler }
166193
val broadcastConnHandler = ConnectionHandler.createBroadcast(
167-
listOf(ConnectionHandler.createStreamHandlerInitializer(allStreamHandlers)) +
168-
connHandlerProtocols +
194+
connHandlerProtocols +
169195
connectionHandlers.values
170196
)
171197
val networkImpl = NetworkImpl(transports, broadcastConnHandler)
@@ -175,9 +201,9 @@ open class Builder {
175201
networkImpl,
176202
addressBook,
177203
network.listen.map { Multiaddr(it) },
178-
protocolsMultistream,
204+
protocols.values,
179205
broadcastConnHandler,
180-
broadcastStreamHandler
206+
streamVisitors
181207
)
182208
}
183209
}
@@ -203,7 +229,7 @@ class AddressBookBuilder {
203229

204230
class TransportsBuilder : Enumeration<TransportCtor>()
205231
class SecureChannelsBuilder : Enumeration<SecureChannelCtor>()
206-
class MuxersBuilder : Enumeration<StreamMuxerCtor>()
232+
class MuxersBuilder : Enumeration<StreamMuxerProtocol>()
207233
class ProtocolsBuilder : Enumeration<ProtocolBinding<Any>>()
208234
class ConnectionHandlerBuilder : Enumeration<ConnectionHandler>()
209235

@@ -212,24 +238,36 @@ class DebugBuilder {
212238
* Injects the [ChannelHandler] to the wire closest point.
213239
* Could be primarily useful for security handshake debugging/monitoring
214240
*/
215-
val beforeSecureHandler = DebugHandlerBuilder("wire.sec.before")
241+
val beforeSecureHandler = DebugHandlerBuilder<Connection>("wire.sec.before")
216242
/**
217243
* Injects the [ChannelHandler] right after the connection cipher
218244
* to handle plain wire messages
219245
*/
220-
val afterSecureHandler = DebugHandlerBuilder("wire.sec.after")
246+
val afterSecureHandler = DebugHandlerBuilder<Connection>("wire.sec.after")
221247
/**
222248
* Injects the [ChannelHandler] right after the [StreamMuxer] pipeline handler
223249
* It intercepts [io.libp2p.mux.MuxFrame] instances
224250
*/
225-
val muxFramesHandler = DebugHandlerBuilder("wire.mux.frames")
251+
val muxFramesHandler = DebugHandlerBuilder<Connection>("wire.mux.frames")
252+
253+
val streamPreHandler = DebugHandlerBuilder<Stream>("wire.stream.pre")
254+
255+
val streamHandler = DebugHandlerBuilder<Stream>("wire.stream")
226256
}
227257

228-
class DebugHandlerBuilder(var name: String) {
229-
var handler: ChannelHandler? = null
258+
class DebugHandlerBuilder<TChannel : P2PChannel>(var name: String) {
259+
val handlers = mutableListOf<ChannelVisitor<TChannel>>()
260+
261+
fun addHandler(handler: ChannelVisitor<TChannel>) {
262+
handlers += handler
263+
}
264+
265+
fun addNettyHandler(handler: ChannelHandler) {
266+
addHandler { it.pushHandler(handler) }
267+
}
230268

231-
fun setLogger(level: LogLevel, loggerName: String = name) {
232-
handler = LoggingHandler(loggerName, level)
269+
fun addLogger(level: LogLevel, loggerName: String = name) {
270+
addNettyHandler(LoggingHandler(loggerName, level))
233271
}
234272
}
235273

0 commit comments

Comments
 (0)