nim-libp2p/libp2p/upgrademngrs/upgrade.nim

72 lines
2.1 KiB
Nim

# Nim-LibP2P
# Copyright (c) 2023-2024 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 gcsafe.}
{.push raises: [].}
import std/[sequtils, strutils]
import pkg/[chronos, chronicles, metrics]
import
../stream/connection,
../protocols/secure/secure,
../protocols/identify,
../muxers/muxer,
../multistream,
../connmanager,
../errors,
../utility
export connmanager, connection, identify, secure, multistream
declarePublicCounter(
libp2p_failed_upgrades_incoming, "incoming connections failed upgrades"
)
declarePublicCounter(
libp2p_failed_upgrades_outgoing, "outgoing connections failed upgrades"
)
logScope:
topics = "libp2p upgrade"
type
UpgradeFailedError* = object of LPError
Upgrade* = ref object of RootObj
ms*: MultistreamSelect
secureManagers*: seq[Secure]
method upgrade*(
self: Upgrade, conn: Connection, peerId: Opt[PeerId]
): Future[Muxer] {.async: (raises: [CancelledError, LPError], raw: true), base.} =
raiseAssert("Not implemented!")
proc secure*(
self: Upgrade, conn: Connection, peerId: Opt[PeerId]
): Future[Connection] {.async: (raises: [CancelledError, LPError]).} =
if self.secureManagers.len <= 0:
raise (ref UpgradeFailedError)(msg: "No secure managers registered!")
let codec =
if conn.dir == Out:
await self.ms.select(conn, self.secureManagers.mapIt(it.codec))
else:
await MultistreamSelect.handle(conn, self.secureManagers.mapIt(it.codec))
if codec.len == 0:
raise (ref UpgradeFailedError)(msg: "Unable to negotiate a secure channel!")
trace "Securing connection", conn, codec
let secureProtocol = self.secureManagers.filterIt(it.codec == codec)
# ms.select should deal with the correctness of this
# let's avoid duplicating checks but detect if it fails to do it properly
doAssert(secureProtocol.len > 0)
await secureProtocol[0].secure(conn, peerId)