use a builder pattern to build the switch (#551)

* use a builder pattern to build the switch

* with with

* more refs
This commit is contained in:
Giovanni Petrantoni 2021-04-02 10:20:51 +09:00 committed by GitHub
parent df497660bc
commit 795a651839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 202 additions and 74 deletions

View File

@ -26,7 +26,7 @@ import
peerid, peerid,
peerinfo, peerinfo,
multiaddress, multiaddress,
standard_setup, builders,
crypto/crypto] crypto/crypto]
import bearssl import bearssl
@ -36,4 +36,4 @@ export
connection, multiaddress, crypto, lpstream, connection, multiaddress, crypto, lpstream,
bufferstream, bearssl, muxer, mplex, transport, bufferstream, bearssl, muxer, mplex, transport,
tcptransport, noise, errors, cid, multihash, tcptransport, noise, errors, cid, multihash,
multicodec, standard_setup multicodec, builders

195
libp2p/builders.nim Normal file
View File

@ -0,0 +1,195 @@
import
options, tables, chronos, bearssl,
switch, peerid, peerinfo, stream/connection, multiaddress,
crypto/crypto, transports/[transport, tcptransport],
muxers/[muxer, mplex/mplex],
protocols/[identify, secure/secure, secure/noise],
connmanager
export
switch, peerid, peerinfo, connection, multiaddress, crypto
type
SecureProtocol* {.pure.} = enum
Noise,
Secio {.deprecated.}
SwitchBuilder* = ref object
privKey: Option[PrivateKey]
address: MultiAddress
secureManagers: seq[SecureProtocol]
tcpTransportFlags: Option[set[ServerFlags]]
rng: ref BrHmacDrbgContext
inTimeout: Duration
outTimeout: Duration
maxConnections: int
maxIn: int
maxOut: int
maxConnsPerPeer: int
protoVersion: Option[string]
agentVersion: Option[string]
proc init*(_: type[SwitchBuilder]): SwitchBuilder =
SwitchBuilder(
privKey: none(PrivateKey),
address: MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet(),
secureManagers: @[],
tcpTransportFlags: block:
let flags: set[ServerFlags] = {}
some(flags),
rng: newRng(),
inTimeout: 5.minutes,
outTimeout: 5.minutes,
maxConnections: MaxConnections,
maxIn: -1,
maxOut: -1,
maxConnsPerPeer: MaxConnectionsPerPeer,
protoVersion: none(string),
agentVersion: none(string))
# so I tried using var inpit and return but did not work...
# as in proc privateKey*(builder: var SwitchBuilder, privateKey: PrivateKey): var SwitchBuilder =
# so in nim we are stuck with this hardly efficient way and hopey compiler figures it out.. heh
# maybe {.byref.} works.... I would not bet on it but let's use it.
proc withPrivateKey*(b: SwitchBuilder, privateKey: PrivateKey): SwitchBuilder =
b.privKey = some(privateKey)
b
proc withAddress*(b: SwitchBuilder, address: MultiAddress): SwitchBuilder =
b.address = address
b
proc withSecureManager*(b: SwitchBuilder, secureManager: SecureProtocol): SwitchBuilder =
b.secureManagers &= secureManager
b
proc withTcpTransport*(b: SwitchBuilder, flags: set[ServerFlags] = {}): SwitchBuilder =
b.tcpTransportFlags = some(flags)
b
proc withRng*(b: SwitchBuilder, rng: ref BrHmacDrbgContext): SwitchBuilder =
b.rng = rng
b
proc withInTimeout*(b: SwitchBuilder, inTimeout: Duration): SwitchBuilder =
b.inTimeout = inTimeout
b
proc withOutTimeout*(b: SwitchBuilder, outTimeout: Duration): SwitchBuilder =
b.outTimeout = outTimeout
b
proc withMaxConnections*(b: SwitchBuilder, maxConnections: int): SwitchBuilder =
b.maxConnections = maxConnections
b
proc withMaxIn*(b: SwitchBuilder, maxIn: int): SwitchBuilder =
b.maxIn = maxIn
b
proc withMaxOut*(b: SwitchBuilder, maxOut: int): SwitchBuilder =
b.maxOut = maxOut
b
proc withMaxConnsPerPeer*(b: SwitchBuilder, maxConnsPerPeer: int): SwitchBuilder =
b.maxConnsPerPeer = maxConnsPerPeer
b
proc withProtoVersion*(b: SwitchBuilder, protoVersion: string): SwitchBuilder =
b.protoVersion = some(protoVersion)
b
proc withAgentVersion*(b: SwitchBuilder, agentVersion: string): SwitchBuilder =
b.agentVersion = some(agentVersion)
b
proc build*(b: SwitchBuilder): Switch =
let
inTimeout = b.inTimeout
outTimeout = b.outTimeout
proc createMplex(conn: Connection): Muxer =
Mplex.init(
conn,
inTimeout = inTimeout,
outTimeout = outTimeout)
if b.rng == nil: # newRng could fail
raise (ref CatchableError)(msg: "Cannot initialize RNG")
let
seckey = b.privKey.get(otherwise = PrivateKey.random(b.rng[]).tryGet())
peerInfo = block:
let info = PeerInfo.init(seckey, [b.address])
if b.protoVersion.isSome():
info.protoVersion = b.protoVersion.get()
if b.agentVersion.isSome():
info.agentVersion = b.agentVersion.get()
info
mplexProvider = newMuxerProvider(createMplex, MplexCodec)
transports = block:
var transports: seq[Transport]
if b.tcpTransportFlags.isSome():
transports &= Transport(TcpTransport.init(b.tcpTransportFlags.get()))
transports
muxers = {MplexCodec: mplexProvider}.toTable
identify = newIdentify(peerInfo)
if b.secureManagers.len == 0:
b.secureManagers &= SecureProtocol.Noise
var
secureManagerInstances: seq[Secure]
for sec in b.secureManagers:
case sec
of SecureProtocol.Noise:
secureManagerInstances &= newNoise(b.rng, seckey).Secure
of SecureProtocol.Secio:
quit("Secio is deprecated!") # use of secio is unsafe
let switch = newSwitch(
peerInfo,
transports,
identify,
muxers,
secureManagers = secureManagerInstances,
maxConnections = b.maxConnections,
maxIn = b.maxIn,
maxOut = b.maxOut,
maxConnsPerPeer = b.maxConnsPerPeer)
return switch
proc newStandardSwitch*(privKey = none(PrivateKey),
address = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet(),
secureManagers: openarray[SecureProtocol] = [
SecureProtocol.Noise,
],
transportFlags: set[ServerFlags] = {},
rng = newRng(),
inTimeout: Duration = 5.minutes,
outTimeout: Duration = 5.minutes,
maxConnections = MaxConnections,
maxIn = -1,
maxOut = -1,
maxConnsPerPeer = MaxConnectionsPerPeer): Switch =
var b = SwitchBuilder
.init()
.withAddress(address)
.withRng(rng)
.withInTimeout(inTimeout)
.withOutTimeout(outTimeout)
.withMaxConnections(maxConnections)
.withMaxIn(maxIn)
.withMaxOut(maxOut)
.withMaxConnsPerPeer(maxConnsPerPeer)
.withTcpTransport(transportFlags)
if privKey.isSome():
b = b.withPrivateKey(privKey.get())
for sm in secureManagers:
b = b.withSecureManager(sm)
b.build()

View File

@ -1,67 +0,0 @@
import
options, tables, chronos, bearssl,
switch, peerid, peerinfo, stream/connection, multiaddress,
crypto/crypto, transports/[transport, tcptransport],
muxers/[muxer, mplex/mplex],
protocols/[identify, secure/secure, secure/noise],
connmanager
export
switch, peerid, peerinfo, connection, multiaddress, crypto
type
SecureProtocol* {.pure.} = enum
Noise,
Secio {.deprecated.}
proc newStandardSwitch*(privKey = none(PrivateKey),
address = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet(),
secureManagers: openarray[SecureProtocol] = [
SecureProtocol.Noise,
],
transportFlags: set[ServerFlags] = {},
rng = newRng(),
inTimeout: Duration = 5.minutes,
outTimeout: Duration = 5.minutes,
maxConnections = MaxConnections,
maxIn = -1,
maxOut = -1,
maxConnsPerPeer = MaxConnectionsPerPeer): Switch =
proc createMplex(conn: Connection): Muxer =
Mplex.init(
conn,
inTimeout = inTimeout,
outTimeout = outTimeout)
if rng == nil: # newRng could fail
raise (ref CatchableError)(msg: "Cannot initialize RNG")
let
seckey = privKey.get(otherwise = PrivateKey.random(rng[]).tryGet())
peerInfo = PeerInfo.init(seckey, [address])
mplexProvider = newMuxerProvider(createMplex, MplexCodec)
transports = @[Transport(TcpTransport.init(transportFlags))]
muxers = {MplexCodec: mplexProvider}.toTable
identify = newIdentify(peerInfo)
var
secureManagerInstances: seq[Secure]
for sec in secureManagers:
case sec
of SecureProtocol.Noise:
secureManagerInstances &= newNoise(rng, seckey).Secure
of SecureProtocol.Secio:
quit("Secio is deprecated!") # use of secio is unsafe
let switch = newSwitch(
peerInfo,
transports,
identify,
muxers,
secureManagers = secureManagerInstances,
maxConnections = maxConnections,
maxIn = maxIn,
maxOut = maxOut,
maxConnsPerPeer = maxConnsPerPeer)
return switch

View File

@ -5,7 +5,7 @@ include ../../libp2p/protocols/pubsub/gossipsub
import options import options
import unittest, bearssl import unittest, bearssl
import stew/byteutils import stew/byteutils
import ../../libp2p/standard_setup import ../../libp2p/builders
import ../../libp2p/errors import ../../libp2p/errors
import ../../libp2p/crypto/crypto import ../../libp2p/crypto/crypto
import ../../libp2p/stream/bufferstream import ../../libp2p/stream/bufferstream

View File

@ -6,13 +6,13 @@ const
import random, tables import random, tables
import chronos import chronos
import ../../libp2p/[standard_setup, import ../../libp2p/[builders,
protocols/pubsub/pubsub, protocols/pubsub/pubsub,
protocols/pubsub/gossipsub, protocols/pubsub/gossipsub,
protocols/pubsub/floodsub, protocols/pubsub/floodsub,
protocols/secure/secure] protocols/secure/secure]
export standard_setup export builders
randomize() randomize()

View File

@ -10,7 +10,7 @@ import ../libp2p/[daemon/daemonapi,
cid, cid,
varint, varint,
multihash, multihash,
standard_setup, builders,
peerid, peerid,
peerinfo, peerinfo,
switch, switch,

View File

@ -7,7 +7,7 @@ import nimcrypto/sysrand
import ../libp2p/[errors, import ../libp2p/[errors,
switch, switch,
multistream, multistream,
standard_setup, builders,
stream/bufferstream, stream/bufferstream,
stream/connection, stream/connection,
multiaddress, multiaddress,