/** * Copyright © 2016 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "manager.hpp" namespace phosphor { namespace inventory { namespace manager { namespace details { /** @brief Fowrarding signal callback. * * Extracts per-signal specific context and forwards the call to the manager * instance. */ auto _signal(sd_bus_message *m, void *data, sd_bus_error *e) noexcept { try { auto msg = sdbusplus::message::message(m); auto &args = *static_cast(data); sd_bus_message_ref(m); auto &mgr = *std::get<0>(args); mgr.signal(msg, *std::get<1>(args)); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } return 0; } } // namespace details Manager::Manager( sdbusplus::bus::bus &&bus, const char *busname, const char *root, const char *iface) : sdbusplus::server::xyz::openbmc_project::Inventory::Manager(bus, root), _shutdown(false), _root(root), _bus(std::move(bus)), _manager(sdbusplus::server::manager::manager(_bus, root)) { for (auto &x: _events) { // Create a callback context for each event. _sigargs.emplace_back( std::make_unique( std::make_tuple( this, &x.second))); // Register our callback and the context for // each event. _matches.emplace_back( sdbusplus::server::match::match( _bus, std::get<0>(x.second), details::_signal, _sigargs.back().get())); } _bus.request_name(busname); } void Manager::shutdown() noexcept { _shutdown = true; } void Manager::run() noexcept { while(!_shutdown) { try { _bus.process_discard(); _bus.wait(5000000); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } } } void Manager::notify(std::string path, Object object) { try { using MakerType = HolderPtr(*)( sdbusplus::bus::bus &, const char *); using Makers = std::map; if(object.cbegin() == object.cend()) throw std::runtime_error( "No interfaces in " + path); static const Makers makers{ // TODO - Add mappings here. }; path.insert(0, _root); auto obj = _refs.find(path); if(obj != _refs.end()) throw std::runtime_error( obj->first + " already exists"); // Create an interface holder for each interface // provided by the client and group them into // a container. InterfaceComposite ref; for (auto &x: object) { auto maker = makers.find(x.first.c_str()); if(maker == makers.end()) throw std::runtime_error( "Unimplemented interface: " + x.first); ref.emplace( std::make_pair( x.first, (maker->second)(_bus, path.c_str()))); } // Hang on to a reference to the object (interfaces) // so it stays on the bus, and so we can make calls // to it if needed. _refs.emplace( std::make_pair( path, std::move(ref))); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } } void Manager::signal(sdbusplus::message::message &msg, auto &args) { auto &filter = std::get<1>(args); auto &action = std::get<2>(args); if(filter(msg, *this)) { action(*this); } } void Manager::destroyObject(const char *path) { std::string p{path}; _refs.erase(_root + p); } } // namespace manager } // namespace inventory } // namespace phosphor // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4