Add sbusplus properties server

Add properties server similar to boost-dbus that allows
for creating dbus interfaces during runtime. This adds
support for creating methods and get / set properties.

Get / set property callbacks are stored in flat_maps of
std::function allowing custom get / set functions. Methods
are also stored in this way allowing for creating of interfaces
without using any yaml. There is one C level callback for properties
get, properties set, and method calls that lookup the correct
std::function in the flat_map to call.

Tested: Ran asio-example on bmc, and updated fru-device.
Change-Id: I19881049f4307fe9c68f78df8854f14afdd6c362
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/example/asio-example.cpp b/example/asio-example.cpp
index 7dde720..82d713e 100644
--- a/example/asio-example.cpp
+++ b/example/asio-example.cpp
@@ -1,9 +1,17 @@
 #include <iostream>
+#include <ctime>
+#include <chrono>
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server.hpp>
 #include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
 #include <boost/asio.hpp>
 
+int foo(int test)
+{
+    return ++test;
+}
+
 int main()
 {
     using GetSubTreeType = std::vector<std::pair<
@@ -59,6 +67,56 @@
         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
         "/org/openbmc/control", 2, std::vector<std::string>());
 
+    // test object server
+    conn->request_name("xyz.openbmc_project.asio-test");
+    auto server = sdbusplus::asio::object_server(conn);
+    std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
+        server.add_interface("/xyz/openbmc_project/test",
+                             "xyz.openbmc_project.test");
+    // test generic properties
+    iface->register_property("int", 33,
+                             sdbusplus::asio::PropertyPermission::readWrite);
+    std::vector<std::string> myStringVec = {"some", "test", "data"};
+    std::vector<std::string> myStringVec2 = {"more", "test", "data"};
+
+    iface->register_property("myStringVec", myStringVec,
+                             sdbusplus::asio::PropertyPermission::readWrite);
+    iface->register_property("myStringVec2", myStringVec2);
+
+    // test properties with specialized callbacks
+    iface->register_property("lessThan50", 23,
+                             // custom set
+                             [](const int& req, int& propertyValue) {
+                                 if (req >= 50)
+                                 {
+                                     return -EINVAL;
+                                 }
+                                 propertyValue = req;
+                                 return 1; // success
+                             });
+    iface->register_property(
+        "TrailTime", std::string("foo"),
+        // custom set
+        [](const std::string& req, std::string& propertyValue) {
+            propertyValue = req;
+            return 1; // success
+        },
+        // custom get
+        [](const std::string& property) {
+            auto now = std::chrono::system_clock::now();
+            auto timePoint = std::chrono::system_clock::to_time_t(now);
+            return property + std::ctime(&timePoint);
+        });
+
+    // test method creation
+    iface->register_method("TestMethod", [](const int32_t& callCount) {
+        return "success: " + std::to_string(callCount);
+    });
+
+    iface->register_method("TestFunction", foo);
+
+    iface->initialize();
+    iface->set_property("int", 45);
     io.run();
 
     return 0;