/** * Copyright Quadrivium LLC * All Rights Reserved * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include // implementations #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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 * * Example 1: Make default network with Yamux as muxer, Plaintext as * security, TCP as transport. * @code * auto injector = makeNetworkInjector(); * std::shared_ptr network = injector.create>(); * assert(network != nullptr); * @endcode * * Example 2: 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(), * useMuxerAdaptors(), * useSecurityAdaptors() * ); * * std::shared_ptr network = injector.create>(); * assert(network != nullptr); * @endcode * * Example 3: Use mocked router: * @code * struct RouterMock : public Router {...}; * * auto injector = makeNetworkInjector( * boost::di::bind.to() * ); * * // build network * std::shared_ptr network = injector.create>(); * assert(network != nullptr); * * // get mock * std::shared_ptr routerMock = injector.create>(); * assert(routerMock != nullptr); * @endcode * * Example 4: Use instance of mock. * @code * struct RouterMock : public Router {...}; * * auto routerMock = std::make_shared(); * * auto injector = makeNetworkInjector( * boost::di::bind.to(routerMock) * ); * * // build network * std::shared_ptr network = injector.create>(); * 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().template 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.template 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({.a = 3}) * ); * @endcode */ template inline auto useConfig(C &&c) { return boost::di::bind>().template to( std::forward(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() * ); * @endcode */ template inline auto useLayerAdaptors() { return boost::di::bind() // NOLINT .template to()[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() * ); * @endcode */ template inline auto useSecurityAdaptors() { return boost::di::bind() // NOLINT .template to()[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 inline auto useMuxerAdaptors() { return boost::di::bind() // NOLINT .template to()[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 inline auto useTransportAdaptors() { return boost::di::bind() // NOLINT .template to()[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 inline auto makeNetworkInjector(Ts &&...args) { namespace di = boost::di; auto csprng = std::make_shared(); auto ed25519_provider = std::make_shared(); auto rsa_provider = std::make_shared(); auto ecdsa_provider = std::make_shared(); auto secp256k1_provider = std::make_shared(csprng); auto hmac_provider = std::make_shared(); std::shared_ptr crypto_provider = std::make_shared(csprng, ed25519_provider, rsa_provider, ecdsa_provider, secp256k1_provider, hmac_provider); auto validator = std::make_shared(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( di::bind.template to(), di::bind().template to(std::move(keypair)), di::bind().template to(std::move(csprng)), di::bind().template to(std::move(ed25519_provider)), di::bind().template to(std::move(rsa_provider)), di::bind().template to(std::move(ecdsa_provider)), di::bind().template to(std::move(secp256k1_provider)), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind.template to(layer::WsConnectionConfig{}), di::bind.template to(layer::WssCertificate{}), di::bind.template to(basic::Scheduler::Config{}), di::bind().template to(), di::bind().template to(), // internal di::bind().template to (), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), di::bind().template to(), // default adaptors di::bind.template to(muxer::MuxedConnectionConfig{}), di::bind().template to(), // NOLINT di::bind().template to(), // NOLINT di::bind().template to(), // NOLINT di::bind().template to(), // NOLINT // user-defined overrides... std::forward(args)... ); // clang-format on } } // namespace libp2p::injector