You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

356 lines
13 KiB

/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <boost/di.hpp>
// implementations
#include <libp2p/basic/scheduler/asio_scheduler_backend.hpp>
#include <libp2p/basic/scheduler/scheduler_impl.hpp>
#include <libp2p/crypto/aes_ctr/aes_ctr_impl.hpp>
#include <libp2p/crypto/crypto_provider/crypto_provider_impl.hpp>
#include <libp2p/crypto/ecdsa_provider/ecdsa_provider_impl.hpp>
#include <libp2p/crypto/ed25519_provider/ed25519_provider_impl.hpp>
#include <libp2p/crypto/hmac_provider/hmac_provider_impl.hpp>
#include <libp2p/crypto/key_marshaller/key_marshaller_impl.hpp>
#include <libp2p/crypto/key_validator/key_validator_impl.hpp>
#include <libp2p/crypto/random_generator/boost_generator.hpp>
#include <libp2p/crypto/rsa_provider/rsa_provider_impl.hpp>
#include <libp2p/crypto/secp256k1_provider/secp256k1_provider_impl.hpp>
#include <libp2p/layer/websocket.hpp>
#include <libp2p/muxer/mplex.hpp>
#include <libp2p/muxer/yamux.hpp>
#include <libp2p/network/impl/connection_manager_impl.hpp>
#include <libp2p/network/impl/dialer_impl.hpp>
#include <libp2p/network/impl/dnsaddr_resolver_impl.hpp>
#include <libp2p/network/impl/listener_manager_impl.hpp>
#include <libp2p/network/impl/network_impl.hpp>
#include <libp2p/network/impl/router_impl.hpp>
#include <libp2p/network/impl/transport_manager_impl.hpp>
#include <libp2p/peer/impl/identity_manager_impl.hpp>
#include <libp2p/protocol_muxer/multiselect.hpp>
#include <libp2p/security/noise.hpp>
#include <libp2p/security/plaintext.hpp>
#include <libp2p/security/plaintext/exchange_message_marshaller_impl.hpp>
#include <libp2p/security/secio.hpp>
#include <libp2p/security/secio/exchange_message_marshaller_impl.hpp>
#include <libp2p/security/secio/propose_message_marshaller_impl.hpp>
#include <libp2p/security/tls.hpp>
#include <libp2p/security/tls/ssl_context.hpp>
#include <libp2p/transport/impl/upgrader_impl.hpp>
#include <libp2p/transport/quic/transport.hpp>
#include <libp2p/transport/tcp.hpp>
// clang-format off
/**
* @file network_injector.hpp
* @brief This header defines DI injector helpers, which can be used instead of
* manual wiring.
*
* The main function in this header is
* @code makeNetworkInjector() @endcode
* Use it to create a Boost.DI container with default types.
*
* By default:
* - TCP is used as transport
* - Plaintext as security
* - Yamux as muxer
* - Random keypair is generated
*
* List of libraries that should be linked to your lib/exe:
* - libp2p_network
* - libp2p_tcp
* - libp2p_yamux
* - libp2p_plaintext
* - libp2p_connection_manager
* - libp2p_transport_manager
* - libp2p_listener_manager
* - libp2p_identity_manager
* - libp2p_dialer
* - libp2p_router
* - multiselect
* - random_generator
* - key_generator
* - marshaller
*
* <b>Example 1</b>: Make default network with Yamux as muxer, Plaintext as
* security, TCP as transport.
* @code
* auto injector = makeNetworkInjector();
* std::shared_ptr<Network> network = injector.create<std::shared_ptr<Network>>();
* assert(network != nullptr);
* @endcode
*
* <b>Example 2</b>: Make network with new transport, muxer and security.
* @code
* struct NewTransport : public TransportAdaptor {...};
* struct NewMuxer : public MuxerAdaptor {...};
* struct NewSecurity : public SecurityAdaptor {...};
*
* auto injector = makeNetworkInjector(
* useTransportAdaptors<NewTransport>(),
* useMuxerAdaptors<NewMuxer>(),
* useSecurityAdaptors<NewSecurity>()
* );
*
* std::shared_ptr<Network> network = injector.create<std::shared_ptr<Network>>();
* assert(network != nullptr);
* @endcode
*
* <b>Example 3</b>: Use mocked router:
* @code
* struct RouterMock : public Router {...};
*
* auto injector = makeNetworkInjector(
* boost::di::bind<Router>.to<RouterMock>()
* );
*
* // build network
* std::shared_ptr<Network> network = injector.create<std::shared_ptr<Network>>();
* assert(network != nullptr);
*
* // get mock
* std::shared_ptr<RouterMock> routerMock = injector.create<std::shared_ptr<RouterMock>>();
* assert(routerMock != nullptr);
* @endcode
*
* <b>Example 4</b>: Use instance of mock.
* @code
* struct RouterMock : public Router {...};
*
* auto routerMock = std::make_shared<RouterMock>();
*
* auto injector = makeNetworkInjector(
* boost::di::bind<Router>.to(routerMock)
* );
*
* // build network
* std::shared_ptr<Network> network = injector.create<std::shared_ptr<Network>>();
* assert(network != nullptr);
* @endcode
*/
// clang-format on
namespace libp2p::injector {
/**
* @brief Instruct injector to use this keypair. Can be used once.
*
* @code
* KeyPair keyPair = {...};
* auto injector = makeNetworkInjector(
* useKeyPair(std::move(keyPair))
* );
* @endcode
*/
inline auto useKeyPair(crypto::KeyPair key_pair) {
return boost::di::bind<crypto::KeyPair>().to(
std::move(key_pair))[boost::di::override];
}
/**
* @brief Instruct injector to use wss ssl server with key and certificates
* from pem. Can be used once.
*/
inline auto useWssPem(std::string_view pem) {
layer::WssCertificate cert;
if (not pem.empty()) {
if (auto cert_res = layer::WssCertificate::make(pem)) {
cert = std::move(cert_res.value());
} else {
SL_WARN(log::createLogger("libp2p::injector::useWssPem"),
"{}",
cert_res.error());
}
}
return boost::di::bind<layer::WssCertificate>.to(
std::move(cert))[boost::di::override];
}
/**
* @brief Instruct injector to use specific config type. Can be used many
* times for different types.
* @tparam C config type
* @param c config instance
* @return injector binding
*
* @code
* // config definition
* struct YamuxConfig {
* int a = 5;
* }
*
* // config consumer definition
* struct Yamux {
* Yamux(YamuxConfig config);
* }
*
* // create injector
* auto injector = makeNetworkInjector(
* // change default value a=5 to a=3
* useConfig<YamuxConfig>({.a = 3})
* );
* @endcode
*/
template <typename C>
inline auto useConfig(C &&c) {
return boost::di::bind<std::decay<C>>().to(
std::forward<C>(c))[boost::di::override];
}
/**
* @brief Bind layer adaptors by type. Can be used once. Technically many
* types can be specified, even the same type, but in the end only 1 instance
* for each type is created.
* @tparam LayerImpl one or many types of layer adaptors to be used
* @return injector binding
*
* @code
* struct SomeNewAdaptor : public LayerAdaptor {...};
*
* auto injector = makeNetworkInjector(
* useLayerAdaptors<WsAdaptor>()
* );
* @endcode
*/
template <typename... AdaptorImpl>
inline auto useLayerAdaptors() {
return boost::di::bind<layer::LayerAdaptor *[]>() // NOLINT
.to<AdaptorImpl...>()[boost::di::override];
}
/**
* @brief Bind security adaptors by type. Can be used once. Technically many
* types can be specified, even the same type, but in the end only 1 instance
* for each type is created.
* @tparam SecImpl one or many types of security adaptors to be used
* @return injector binding
*
* @code
* struct SomeNewAdaptor : public SecurityAdaptor {...};
*
* auto injector = makeNetworkInjector(
* useSecurityAdaptors<Plaintext, SomeNewAdaptor, SecioAdaptor>()
* );
* @endcode
*/
template <typename... SecImpl>
inline auto useSecurityAdaptors() {
return boost::di::bind<security::SecurityAdaptor *[]>() // NOLINT
.to<SecImpl...>()[boost::di::override];
}
/**
* @brief Bind muxer adaptors by types. Can be used once. Technically many
* types can be specified, even the same type, but in the end only 1 instance
* for each type is created.
* @tparam MuxerImpl one or many types of muxer adaptors to be used
* @return injector binding
*/
template <typename... MuxerImpl>
inline auto useMuxerAdaptors() {
return boost::di::bind<muxer::MuxerAdaptor *[]>() // NOLINT
.to<MuxerImpl...>()[boost::di::override];
}
/**
* @brief Instruct injector to use these transports. Can be used once.
* Technically many types can be specified, even the same type, but in the end
* only 1 instance for each type is created.
* @tparam TransportImpl one or many types of transport adaptors to be used
* @return injector binding
*/
template <typename... TransportImpl>
inline auto useTransportAdaptors() {
return boost::di::bind<transport::TransportAdaptor *[]>() // NOLINT
.to<TransportImpl...>()[boost::di::override];
}
/**
* @brief Main function that creates Network Injector.
* @tparam Ts types of injector bindings
* @param args injector bindings that override default bindings.
* @return complete network injector
*/
template <typename InjectorConfig = BOOST_DI_CFG, typename... Ts>
inline auto makeNetworkInjector(Ts &&...args) {
namespace di = boost::di;
auto csprng = std::make_shared<crypto::random::BoostRandomGenerator>();
auto ed25519_provider =
std::make_shared<crypto::ed25519::Ed25519ProviderImpl>();
auto rsa_provider = std::make_shared<crypto::rsa::RsaProviderImpl>();
auto ecdsa_provider = std::make_shared<crypto::ecdsa::EcdsaProviderImpl>();
auto secp256k1_provider =
std::make_shared<crypto::secp256k1::Secp256k1ProviderImpl>(csprng);
auto hmac_provider = std::make_shared<crypto::hmac::HmacProviderImpl>();
std::shared_ptr<crypto::CryptoProvider> crypto_provider =
std::make_shared<crypto::CryptoProviderImpl>(csprng,
ed25519_provider,
rsa_provider,
ecdsa_provider,
secp256k1_provider,
hmac_provider);
auto validator =
std::make_shared<crypto::validator::KeyValidatorImpl>(crypto_provider);
// assume no error here. otherwise... just blow up executable
auto keypair =
crypto_provider->generateKeys(crypto::Key::Type::Ed25519).value();
// clang-format off
return di::make_injector<InjectorConfig>(
di::bind<crypto::random::RandomGenerator>.to<crypto::random::BoostRandomGenerator>(),
di::bind<crypto::KeyPair>().to(std::move(keypair)),
di::bind<crypto::random::CSPRNG>().to(std::move(csprng)),
di::bind<crypto::ed25519::Ed25519Provider>().to(std::move(ed25519_provider)),
di::bind<crypto::rsa::RsaProvider>().to(std::move(rsa_provider)),
di::bind<crypto::ecdsa::EcdsaProvider>().to(std::move(ecdsa_provider)),
di::bind<crypto::secp256k1::Secp256k1Provider>().to(std::move(secp256k1_provider)),
di::bind<crypto::aes::AesCtr>().to<crypto::aes::AesCtrImpl>(),
di::bind<crypto::hmac::HmacProvider>().to<crypto::hmac::HmacProviderImpl>(),
di::bind<crypto::CryptoProvider>().to<crypto::CryptoProviderImpl>(),
di::bind<crypto::marshaller::KeyMarshaller>().to<crypto::marshaller::KeyMarshallerImpl>(),
di::bind<peer::IdentityManager>().to<peer::IdentityManagerImpl>(),
di::bind<crypto::validator::KeyValidator>().to<crypto::validator::KeyValidatorImpl>(),
di::bind<security::plaintext::ExchangeMessageMarshaller>().to<security::plaintext::ExchangeMessageMarshallerImpl>(),
di::bind<security::secio::ProposeMessageMarshaller>().to<security::secio::ProposeMessageMarshallerImpl>(),
di::bind<security::secio::ExchangeMessageMarshaller>().to<security::secio::ExchangeMessageMarshallerImpl>(),
di::bind<layer::WsConnectionConfig>.to(layer::WsConnectionConfig{}),
di::bind<layer::WssCertificate>.to(layer::WssCertificate{}),
di::bind<basic::Scheduler::Config>.to(basic::Scheduler::Config{}),
di::bind<basic::SchedulerBackend>().to<basic::AsioSchedulerBackend>(),
di::bind<basic::Scheduler>().to<basic::SchedulerImpl>(),
// internal
di::bind<network::DnsaddrResolver>().to <network::DnsaddrResolverImpl>(),
di::bind<network::Router>().to<network::RouterImpl>(),
di::bind<network::ConnectionManager>().to<network::ConnectionManagerImpl>(),
di::bind<network::ListenerManager>().to<network::ListenerManagerImpl>(),
di::bind<network::Dialer>().to<network::DialerImpl>(),
di::bind<network::Network>().to<network::NetworkImpl>(),
di::bind<network::TransportManager>().to<network::TransportManagerImpl>(),
di::bind<transport::Upgrader>().to<transport::UpgraderImpl>(),
di::bind<protocol_muxer::ProtocolMuxer>().to<protocol_muxer::multiselect::Multiselect>(),
// default adaptors
di::bind<muxer::MuxedConnectionConfig>.to(muxer::MuxedConnectionConfig{}),
di::bind<layer::LayerAdaptor *[]>().to<layer::WsAdaptor, layer::WssAdaptor>(), // NOLINT
di::bind<security::SecurityAdaptor *[]>().to<security::Plaintext, security::Secio, security::Noise, security::TlsAdaptor>(), // NOLINT
di::bind<muxer::MuxerAdaptor *[]>().to<muxer::Yamux, muxer::Mplex>(), // NOLINT
di::bind<transport::TransportAdaptor *[]>().to<transport::TcpTransport, transport::QuicTransport>(), // NOLINT
// user-defined overrides...
std::forward<decltype(args)>(args)...
);
// clang-format on
}
} // namespace libp2p::injector