nim-libp2p-experimental/libp2p/builders.nim

235 lines
6.3 KiB
Nim

## Nim-Libp2p
## Copyright (c) 2020 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
## at your option.
## This file may not be copied, modified, or distributed except according to
## those terms.
{.push raises: [Defect].}
import
options, tables, chronos, chronicles, bearssl,
switch, peerid, peerinfo, stream/connection, multiaddress,
crypto/crypto, transports/[transport, tcptransport],
muxers/[muxer, mplex/mplex],
protocols/[identify, secure/secure, secure/noise],
connmanager, upgrademngrs/muxedupgrade,
nameresolving/nameresolver,
errors
export
switch, peerid, peerinfo, connection, multiaddress, crypto, errors
type
TransportProvider* = proc(upgr: Upgrade): Transport {.gcsafe, raises: [Defect].}
SecureProtocol* {.pure.} = enum
Noise,
Secio {.deprecated.}
MplexOpts = object
enable: bool
newMuxer: MuxerConstructor
SwitchBuilder* = ref object
privKey: Option[PrivateKey]
addresses: seq[MultiAddress]
secureManagers: seq[SecureProtocol]
mplexOpts: MplexOpts
transports: seq[TransportProvider]
rng: ref BrHmacDrbgContext
maxConnections: int
maxIn: int
maxOut: int
maxConnsPerPeer: int
protoVersion: string
agentVersion: string
nameResolver: NameResolver
proc new*(T: type[SwitchBuilder]): T =
let address = MultiAddress
.init("/ip4/127.0.0.1/tcp/0")
.expect("Should initialize to default")
SwitchBuilder(
privKey: none(PrivateKey),
addresses: @[address],
secureManagers: @[],
maxConnections: MaxConnections,
maxIn: -1,
maxOut: -1,
maxConnsPerPeer: MaxConnectionsPerPeer,
protoVersion: ProtoVersion,
agentVersion: AgentVersion)
proc withPrivateKey*(b: SwitchBuilder, privateKey: PrivateKey): SwitchBuilder =
b.privKey = some(privateKey)
b
proc withAddress*(b: SwitchBuilder, address: MultiAddress): SwitchBuilder =
b.addresses = @[address]
b
proc withAddresses*(b: SwitchBuilder, addresses: seq[MultiAddress]): SwitchBuilder =
b.addresses = addresses
b
proc withMplex*(b: SwitchBuilder, inTimeout = 5.minutes, outTimeout = 5.minutes): SwitchBuilder =
proc newMuxer(conn: Connection): Muxer =
Mplex.new(
conn,
inTimeout = inTimeout,
outTimeout = outTimeout)
b.mplexOpts = MplexOpts(
enable: true,
newMuxer: newMuxer,
)
b
proc withNoise*(b: SwitchBuilder): SwitchBuilder =
b.secureManagers.add(SecureProtocol.Noise)
b
proc withTransport*(b: SwitchBuilder, prov: TransportProvider): SwitchBuilder =
b.transports.add(prov)
b
proc withTcpTransport*(b: SwitchBuilder, flags: set[ServerFlags] = {}): SwitchBuilder =
b.withTransport(proc(upgr: Upgrade): Transport = TcpTransport.new(flags, upgr))
proc withRng*(b: SwitchBuilder, rng: ref BrHmacDrbgContext): SwitchBuilder =
b.rng = rng
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 = protoVersion
b
proc withAgentVersion*(b: SwitchBuilder, agentVersion: string): SwitchBuilder =
b.agentVersion = agentVersion
b
proc withNameResolver*(b: SwitchBuilder, nameResolver: NameResolver): SwitchBuilder =
b.nameResolver = nameResolver
b
proc build*(b: SwitchBuilder): Switch
{.raises: [Defect, LPError].} =
if b.rng == nil: # newRng could fail
raise newException(Defect, "Cannot initialize RNG")
let pkRes = PrivateKey.random(b.rng[])
let
seckey = b.privKey.get(otherwise = pkRes.expect("Expected default Private Key"))
var
secureManagerInstances: seq[Secure]
if SecureProtocol.Noise in b.secureManagers:
secureManagerInstances.add(Noise.new(b.rng, seckey).Secure)
let
peerInfo = PeerInfo.new(
seckey,
b.addresses,
protoVersion = b.protoVersion,
agentVersion = b.agentVersion)
let
muxers = block:
var muxers: Table[string, MuxerProvider]
if b.mplexOpts.enable:
muxers[MplexCodec] = MuxerProvider.new(b.mplexOpts.newMuxer, MplexCodec)
muxers
let
identify = Identify.new(peerInfo)
connManager = ConnManager.new(b.maxConnsPerPeer, b.maxConnections, b.maxIn, b.maxOut)
ms = MultistreamSelect.new()
muxedUpgrade = MuxedUpgrade.new(identify, muxers, secureManagerInstances, connManager, ms)
let
transports = block:
var transports: seq[Transport]
for tProvider in b.transports:
transports.add(tProvider(muxedUpgrade))
transports
if b.secureManagers.len == 0:
b.secureManagers &= SecureProtocol.Noise
if isNil(b.rng):
b.rng = newRng()
let switch = newSwitch(
peerInfo = peerInfo,
transports = transports,
identity = identify,
muxers = muxers,
secureManagers = secureManagerInstances,
connManager = connManager,
ms = ms,
nameResolver = b.nameResolver)
return switch
proc newStandardSwitch*(
privKey = none(PrivateKey),
addrs: MultiAddress | seq[MultiAddress] = 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,
nameResolver: NameResolver = nil): Switch
{.raises: [Defect, LPError].} =
if SecureProtocol.Secio in secureManagers:
quit("Secio is deprecated!") # use of secio is unsafe
let addrs = when addrs is MultiAddress: @[addrs] else: addrs
var b = SwitchBuilder
.new()
.withAddresses(addrs)
.withRng(rng)
.withMaxConnections(maxConnections)
.withMaxIn(maxIn)
.withMaxOut(maxOut)
.withMaxConnsPerPeer(maxConnsPerPeer)
.withMplex(inTimeout, outTimeout)
.withTcpTransport(transportFlags)
.withNameResolver(nameResolver)
.withNoise()
if privKey.isSome():
b = b.withPrivateKey(privKey.get())
b.build()