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,
peerinfo,
multiaddress,
standard_setup,
builders,
crypto/crypto]
import bearssl
@ -36,4 +36,4 @@ export
connection, multiaddress, crypto, lpstream,
bufferstream, bearssl, muxer, mplex, transport,
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 unittest, bearssl
import stew/byteutils
import ../../libp2p/standard_setup
import ../../libp2p/builders
import ../../libp2p/errors
import ../../libp2p/crypto/crypto
import ../../libp2p/stream/bufferstream

View File

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

View File

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

View File

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