[AMBClient] - added time sync message
authorKevron Rees <tripzero.kev@gmail.com>
Wed, 4 Feb 2015 16:39:53 +0000 (08:39 -0800)
committerKevron Rees <tripzero.kev@gmail.com>
Wed, 4 Feb 2015 16:39:53 +0000 (08:39 -0800)
README.md
lib/superptr.hpp
lib/timestamp.h
plugins/common/jsonprotocol.cpp
plugins/common/jsonprotocol.h
tests/testProtocol.cpp
tests/testProtocolClient.cpp

index 7f07113..41a3b0a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@ You will also need to edit your config to enable the Qt-based mainloop:
 
 ~~~~~~~~~~~~~{.json}
 {
-       "mainloop" : "/usr/lib/i386-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
+       "mainloop" : "/usr/lib/x86_64-linux-gnu/automotive-message-broker/qtmainloopplugin.so",
        "plugins" : "/etc/ambd/plugins.d"
 }
 ~~~~~~~~~~~~~
index b2c2f53..afe0983 100644 (file)
@@ -86,6 +86,11 @@ template<typename T> ::std::unique_ptr<T> make_unique(T* t)
   return ::std::unique_ptr<T>(t);
 }
 
+template<typename T> ::std::shared_ptr<T> make_shared(T* t)
+{
+       return ::std::shared_ptr<T>(t);
+}
+
 template<typename T> gobject_ptr<T> make_gobject(T* t)
 {
        return gobject_ptr<T>(t, [](auto ptr) { if(ptr) g_object_unref(ptr);});
index 5300488..7d553b1 100644 (file)
@@ -6,19 +6,44 @@ namespace amb {
 
 double currentTime();
 
+/*!
+ * \brief The Timestamp class provides system time and monotonic time helper functions
+ * Timestamp is meant to be a singleton class.  Access through instance().
+ * \code
+ * double currentMonotonicTime = amb::Timestamp::instance()->currentTime();
+ * double epocTimeForMonotonicTime = amb::Timestamp::instance()->epochTime(currentMonotonicTime);
+ * \endcode
+ */
 class Timestamp {
 protected:
        Timestamp();
 
 public:
 
+       /*!
+        * \brief currentTime
+        * \return current monotonic (steady) time in seconds.
+        */
        double currentTime();
 
+       /*!
+        * \brief epochTime
+        * \param time monotonic time usually from currentTime()
+        * \return number of seconds.milliseconds since unix epoch
+        */
        double epochTime(double time);
 
+       /*!
+        * \brief epochTime
+        * \return current system time in seconds since unix epoch
+        */
        double epochTime();
 
 public:
+       /*!
+        * \brief instance
+        * \return instance of Timestamp;
+        */
        static Timestamp *instance();
 
 private:
index 1d7eda2..9406997 100644 (file)
@@ -27,7 +27,7 @@ bool readCallback(GIOChannel *source, GIOCondition condition, gpointer data)
 }
 
 amb::AmbRemoteClient::AmbRemoteClient(AbstractIo *io)
-       :BaseJsonMessageReader(io)
+       :BaseJsonMessageReader(io), serverTimeOffset(0)
 {
 
 }
@@ -61,19 +61,19 @@ void amb::AmbRemoteClient::get(const string &objectName, const string &sourceUui
        GetMethodCall getCall;
        getCall.sourceUuid = sourceUuid;
        getCall.zone = zone;
-       getCall.value = Object(objectName);
+       getCall.value = amb::make_shared(new Object(objectName));
 
        mGetMethodCalls[getCall.messageId] = cb;
 
        send(getCall);
 }
 
-void amb::AmbRemoteClient::set(const string &objectName, const Object & value, SetCallback cb)
+void amb::AmbRemoteClient::set(const string &objectName, Object::ObjectPtr value, SetCallback cb)
 {
        set(objectName, value, "", Zone::None, cb);
 }
 
-void amb::AmbRemoteClient::set(const string &objectName, const Object & value, const string &sourceUuid, Zone::Type zone, SetCallback cb)
+void amb::AmbRemoteClient::set(const string &objectName, Object::ObjectPtr value, const string &sourceUuid, Zone::Type zone, SetCallback cb)
 {
        SetMethodCall setCall;
        setCall.sourceUuid = sourceUuid;
@@ -85,65 +85,120 @@ void amb::AmbRemoteClient::set(const string &objectName, const Object & value, c
        send(setCall);
 }
 
-void amb::AmbRemoteClient::listen(const string &objectName, const string &sourceUuid, Zone::Type zone, amb::AmbRemoteClient::ObjectCallback cb)
+const string amb::AmbRemoteClient::subscribe(const string &objectName, const string &sourceUuid, Zone::Type zone, amb::AmbRemoteClient::ObjectCallback cb)
 {
+       std::string subscription = createSubscriptionId(objectName, sourceUuid, zone);
 
+       SubscribeMethodCall call(objectName);
+
+       Subscription sub(call, cb);
+
+       mSubscriptions[subscription].push_back(sub);
+
+       return call.messageId;
+}
+
+void amb::AmbRemoteClient::subscribe(const string &objectName, amb::AmbRemoteClient::ObjectCallback cb)
+{
+       subscribe(objectName, "", Zone::None, cb);
 }
 
-void amb::AmbRemoteClient::listen(const string &objectName, amb::AmbRemoteClient::ObjectCallback cb)
+void amb::AmbRemoteClient::unsubscribe(const string &subscribeId)
 {
+       for(auto i : mSubscriptions)
+       {
+               auto subscriptions = &i.second;
+               for(auto n : *subscriptions)
+               {
+                       if(n.subscriptionId() == subscribeId)
+                       {
+                               removeOne(subscriptions, n);
 
+                               if(!subscriptions->size())
+                               {
+                                       UnsubscribeMethodCall call(n.call);
+
+                                       send(call);
+                               }
+                       }
+               }
+       }
 }
 
 void amb::AmbRemoteClient::hasJsonMessage(const picojson::value &json)
 {
        DebugOut(7) << "json: " << json.serialize() << endl;
 
-       if(BaseMessage::is<MethodCall>(json))
+       if(BaseMessage::is<MethodReply<MethodCall>>(json))
        {
-               if(BaseMessage::is<ListMethodCall>(json))
+               if(BaseMessage::is<MethodReply<ListMethodCall>>(json))
                {
-                       ListMethodCall listMethodCall;
-                       listMethodCall.fromJson(json);
+                       MethodReply<ListMethodCall> listMethodReply;
+                       listMethodReply.fromJson(json);
+
+                       const ListMethodCallPtr listMethod = listMethodReply.method();
 
-                       if(mListCalls.find(listMethodCall.messageId) != mListCalls.end())
+                       if(amb::containsKey(mListCalls, listMethod->messageId))
                        {
-                               auto cb = mListCalls[listMethodCall.messageId];
+                               auto cb = mListCalls[listMethod->messageId];
 
                                try
                                {
-                                       cb(listMethodCall.objectNames);
+                                       cb(listMethod->objectNames);
                                }
                                catch(...)
                                {
                                        DebugOut(DebugOut::Warning) << "callback for 'list' is not valid" << endl;
                                }
 
-                               mListCalls.erase(listMethodCall.messageId);
+                               mListCalls.erase(listMethod->messageId);
                        }
                }
-               else if(BaseMessage::is<GetMethodCall>(json))
+               else if(BaseMessage::is<MethodReply<GetMethodCall>>(json))
                {
-                       GetMethodCall getCall;
-                       getCall.fromJson(json);
+                       MethodReply<GetMethodCall> reply;
+                       reply.fromJson(json);
+                       GetMethodCallPtr getCall = reply.method();
 
-                       if(amb::containsKey(mGetMethodCalls, getCall.messageId))
+                       if(amb::containsKey(mGetMethodCalls, getCall->messageId))
                        {
-                               auto cb = mGetMethodCalls[getCall.messageId];
+                               auto cb = mGetMethodCalls[getCall->messageId];
 
                                try
                                {
-                                       cb(getCall.value);
+                                       cb(getCall->value);
                                }
                                catch(...)
                                {
                                        DebugOut(DebugOut::Warning) << "Invalid Get callback " << endl;
                                }
 
-                               mGetMethodCalls.erase(getCall.messageId);
+                               mGetMethodCalls.erase(getCall->messageId);
                        }
                }
-               else if(BaseMessage::is<SetMethodCall>(json))
+               else if(BaseMessage::is<MethodReply<SetMethodCall>>(json))
+               {
+                       MethodReply<SetMethodCall> reply;
+                       reply.fromJson(json);
+
+                       auto call = reply.method();
+
+                       if(amb::containsKey(mSetMethodCalls, call->messageId))
+                       {
+                               auto cb = mSetMethodCalls[call->messageId];
+
+                               try
+                               {
+                                       cb(reply.methodSuccess);
+                               }
+                               catch(...)
+                               {
+                                       DebugOut(DebugOut::Warning) << "Invalid Set callback " << endl;
+                               }
+                               mSetMethodCalls.erase(call->messageId);
+                       }
+               }
+               else if(BaseMessage::is<MethodReply<TimeSyncMessage>>(json))
                {
 
                }
@@ -228,7 +283,7 @@ bool amb::ListMethodCall::fromJson(const picojson::value &json)
                }
                picojson::object obj = i.get<picojson::object>();
 
-               Object ambObj = Object::fromJson(obj);
+               Object::ObjectPtr ambObj = Object::fromJson(obj);
 
                objectNames.push_back(ambObj);
        }
@@ -310,7 +365,6 @@ picojson::value amb::MethodCall::toJson()
 
        obj["source"] = picojson::value(sourceUuid);
        obj["zone"] = picojson::value((double)zone);
-       obj["methodSuccess"] = picojson::value(success);
 
        return picojson::value(obj);
 }
@@ -323,9 +377,6 @@ bool amb::MethodCall::fromJson(const picojson::value &json)
        sourceUuid = json.get("source").to_str();
        zone = json.get("zone").get<double>();
 
-       if(json.contains("success"))
-               success = json.get("methodSuccess").get<bool>();
-
        return true;
 }
 
@@ -393,22 +444,27 @@ amb::AmbRemoteServer::AmbRemoteServer(AbstractIo *io, AbstractRoutingEngine *re)
 
 }
 
-void amb::AmbRemoteServer::list(ListMethodCall &call)
+void amb::AmbRemoteServer::list(ListMethodCallPtr call)
 {
 
 }
 
-void amb::AmbRemoteServer::get(GetMethodCall & get)
+void amb::AmbRemoteServer::get(GetMethodCallPtr get)
 {
 
 }
 
-void amb::AmbRemoteServer::set()
+void amb::AmbRemoteServer::set(SetMethodCallPtr set)
 {
 
 }
 
-void amb::AmbRemoteServer::listen()
+void amb::AmbRemoteServer::subscribe(SubscribeMethodCallPtr call)
+{
+
+}
+
+void amb::AmbRemoteServer::unsubscribe(amb::UnsubscribeMethodCallPtr call)
 {
 
 }
@@ -427,19 +483,63 @@ void amb::AmbRemoteServer::hasJsonMessage(const picojson::value &json)
        {
                if(BaseMessage::is<ListMethodCall>(json))
                {
-                       ListMethodCall listCall;
-
-                       listCall.fromJson(json);
+                       ListMethodCallPtr listCall = BaseMessage::create<ListMethodCall>();
+                       listCall->fromJson(json);
 
                        list(listCall);
                }
                else if(BaseMessage::is<GetMethodCall>(json))
                {
-                       GetMethodCall getCall;
-                       getCall.fromJson(json);
+                       GetMethodCallPtr getCall = BaseMessage::create<GetMethodCall>();
+                       getCall->fromJson(json);
 
                        get(getCall);
                }
+               else if(BaseMessage::is<SetMethodCall>(json))
+               {
+                       SetMethodCallPtr setCall = BaseMessage::create<SetMethodCall>();
+                       setCall->fromJson(json);
+
+                       set(setCall);
+               }
+               else if(BaseMessage::is<SubscribeMethodCall>(json))
+               {
+                       SubscribeMethodCallPtr call = BaseMessage::create<SubscribeMethodCall>();
+                       call->fromJson(json);
+
+                       subscribe(call);
+               }
+               else if(BaseMessage::is<UnsubscribeMethodCall>(json))
+               {
+                       UnsubscribeMethodCallPtr call = BaseMessage::create<UnsubscribeMethodCall>();
+                       call->fromJson(json);
+
+                       unsubscribe(call);
+               }
+               else if(BaseMessage::is<TimeSyncMessage>(json))
+               {
+                       TimeSyncMessagePtr call(new TimeSyncMessage);
+                       call->fromJson(json);
+
+                       call->serverTime = amb::Timestamp::instance()->epochTime();
+
+                       MethodReply<TimeSyncMessage> reply(call, true);
+
+                       send(reply);
+               }
+               else
+               {
+                       BaseMessage call;
+                       call.fromJson(json);
+                       DebugOut(DebugOut::Warning) << "Unhandled method call: " << call.name << endl;
+               }
+       }
+       else
+       {
+               BaseMessage message;
+               message.fromJson(json);
+
+               DebugOut(DebugOut::Warning) << "Unhandled message: type: " << message.type << " name: " << message.name << endl;
        }
 }
 
@@ -462,31 +562,31 @@ bool amb::GetMethodCall::fromJson(const picojson::value &json)
 }
 
 
-amb::Object amb::Object::fromJson(const picojson::object &obj)
+amb::Object::ObjectPtr amb::Object::fromJson(const picojson::object &obj)
 {
        if(!amb::containsKey(obj, "interfaceName"))
        {
                DebugOut(DebugOut::Warning) << "object missing interfaceName" << endl;
-               return Object();
+               return ObjectPtr(new Object());
        }
-       Object ambObj(obj.at("interfaceName").to_str());
+       Object * ambObj = new Object(obj.at("interfaceName").to_str());
 
        for(auto i : obj)
        {
                if(i.second.is<picojson::object>())
                {
-                       ambObj[i.first] = std::shared_ptr<AbstractPropertyType>(amb::jsonToProperty(i.second));
+                       (*ambObj)[i.first] = std::shared_ptr<AbstractPropertyType>(amb::jsonToProperty(i.second));
                }
        }
 
-       return ambObj;
+       return ObjectPtr(ambObj);
 }
 
-picojson::value amb::Object::toJson(const amb::Object &obj)
+picojson::value amb::Object::toJson(const ObjectPtr &obj)
 {
        picojson::object jsonObj;
-       jsonObj["interfaceName"] = picojson::value(obj.interfaceName);
-       for(auto i : obj)
+       jsonObj["interfaceName"] = picojson::value(obj->interfaceName);
+       for(auto i : *obj.get())
        {
                jsonObj[i.first] = i.second->toJson();
        }
@@ -511,4 +611,50 @@ bool amb::SetMethodCall::fromJson(const picojson::value &json)
        MethodCall::fromJson(json);
 
        value = Object::fromJson(json.get<picojson::object>());
+
+       return true;
+}
+
+
+picojson::value amb::SubscribeMethodCall::toJson()
+{
+       auto json = MethodCall::toJson();
+
+       auto obj = json.get<picojson::object>();
+
+       obj["interfaceName"] = picojson::value(interfaceName);
+
+       return picojson::value(obj);
+}
+
+bool amb::SubscribeMethodCall::fromJson(const picojson::value &json)
+{
+       if(!MethodCall::fromJson(json))
+               return false;
+
+       interfaceName = json.get("interfaceName").to_str();
+
+       return true;
+}
+
+
+picojson::value amb::TimeSyncMessage::toJson()
+{
+       auto val = BaseMessage::toJson();
+
+       auto obj = val.get<picojson::object>();
+
+       obj["serverTime"] = picojson::value(serverTime);
+
+       return picojson::value(obj);
+}
+
+bool amb::TimeSyncMessage::fromJson(const picojson::value &json)
+{
+       if(!BaseMessage::fromJson(json))
+               return false;
+
+       serverTime = json.get("serverTime").get<double>();
+
+       return true;
 }
index e851929..cae7200 100644 (file)
@@ -40,6 +40,8 @@ namespace amb
 class Object : public std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>
 {
 public:
+       typedef std::shared_ptr<Object> ObjectPtr;
+
        Object(): std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>() { }
        Object(const std::string & ifaceName): std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>(),
                interfaceName(ifaceName)
@@ -47,12 +49,11 @@ public:
 
        }
 
-       static Object fromJson(const picojson::object & obj);
+       static ObjectPtr fromJson(const picojson::object & obj);
 
-       static picojson::value toJson(const Object & obj);
+       static picojson::value toJson(const ObjectPtr & obj);
 
        std::string interfaceName;
-
 };
 
 class BaseMessage
@@ -97,6 +98,12 @@ public:
                return T::is(json);
        }
 
+       template <class T>
+       static std::shared_ptr<T> create()
+       {
+               return std::shared_ptr<T>(new T());
+       }
+
 protected:
 
        picojson::value data;
@@ -108,13 +115,13 @@ class MethodCall : public BaseMessage
 {
 public:
        MethodCall(std::string name)
-               :BaseMessage(name, "method"), zone(Zone::None), success(false)
+               :BaseMessage(name, "method"), zone(Zone::None)
        {
 
        }
 
        MethodCall(const BaseMessage & other)
-               :BaseMessage(other), zone(Zone::None), success(false)
+               :BaseMessage(other), zone(Zone::None)
        {
                name = other.name;
        }
@@ -124,7 +131,6 @@ public:
        {
                sourceUuid = other.sourceUuid;
                zone = other.zone;
-               success = other.success;
        }
 
        static bool is(const BaseMessage * msg)
@@ -149,7 +155,45 @@ public:
 
        std::string sourceUuid;
        Zone::Type zone;
-       bool success;
+};
+
+template <class T>
+class MethodReply
+{
+public:
+
+       MethodReply(): MethodReply(nullptr, false) {}
+       MethodReply(std::shared_ptr<T> t, bool success): mMethod(t), methodSuccess(success) { }
+       bool methodSuccess;
+
+       picojson::value toJson()
+       {
+               picojson::value v = mMethod->toJson();
+
+               picojson::object obj = v.get<picojson::object>();
+               obj["methodSuccess"] = picojson::value(methodSuccess);
+
+               return picojson::value(obj);
+       }
+
+       bool fromJson(const picojson::value & json)
+       {
+               if(!mMethod) mMethod = std::shared_ptr<T>(new T());
+               mMethod->fromJson(json);
+               methodSuccess = json.get("methodSuccess").get<bool>();
+
+               return true;
+       }
+
+       static bool is(const picojson::value & v)
+       {
+               return v.contains("methodSuccess") && T::is(v);
+       }
+
+       const std::shared_ptr<T> method() { return mMethod; }
+
+protected:
+       std::shared_ptr<T> mMethod;
 };
 
 class ListMethodCall : public MethodCall
@@ -166,7 +210,7 @@ public:
        picojson::value toJson();
        bool fromJson(const picojson::value &json);
 
-       std::vector<Object> objectNames;
+       std::vector<Object::ObjectPtr> objectNames;
 
        static bool is(const BaseMessage * msg)
        {
@@ -201,7 +245,7 @@ public:
                return json.get("name").to_str() == "get";
        }
 
-       Object value;
+       Object::ObjectPtr value;
 };
 
 class SetMethodCall : public MethodCall
@@ -223,10 +267,100 @@ public:
 
        static bool is(const picojson::value & json)
        {
-               return json.get("name").to_str() != "set";
+               return json.get("name").to_str() == "set";
+       }
+
+       Object::ObjectPtr value;
+};
+
+class SubscribeMethodCall : virtual public MethodCall
+{
+public:
+       SubscribeMethodCall()
+               :SubscribeMethodCall("")
+       {
+
+       }
+       SubscribeMethodCall(const std::string & ifaceName)
+               :MethodCall("subscribe"), interfaceName(ifaceName)
+       {
+
+       }
+
+       picojson::value toJson();
+       bool fromJson(const picojson::value &json);
+
+       static bool is(const BaseMessage *msg)
+       {
+               return msg->name == "subscribe";
+       }
+
+       static bool is(const picojson::value & json)
+       {
+               return json.get("name").to_str() == "subscribe";
+       }
+
+       std::string interfaceName;
+};
+
+class UnsubscribeMethodCall : virtual public MethodCall, public SubscribeMethodCall
+{
+public:
+       UnsubscribeMethodCall()
+               :UnsubscribeMethodCall("")
+       {
+
+       }
+
+       UnsubscribeMethodCall(const SubscribeMethodCall & call)
+               : UnsubscribeMethodCall(call.interfaceName)
+       {
+               sourceUuid = call.sourceUuid;
+               zone = call.zone;
+       }
+
+       UnsubscribeMethodCall(const std::string & ifaceName)
+               :MethodCall("unsubscribe"), interfaceName(ifaceName)
+       {
+
+       }
+
+       static bool is(const BaseMessage *msg)
+       {
+               return msg->name == "unsubscribe";
+       }
+
+       static bool is(const picojson::value & json)
+       {
+               return json.get("name").to_str() == "unsubscribe";
+       }
+
+       std::string interfaceName;
+};
+
+class TimeSyncMessage : public BaseMessage
+{
+public:
+       TimeSyncMessage()
+               :BaseMessage("timeSync", "message"), serverTime(0)
+       {
+
+       }
+
+       double serverTime;
+
+       picojson::value toJson();
+       bool fromJson(const picojson::value &json);
+
+       static bool is(const BaseMessage & msg)
+       {
+               return msg.type == "timeSync" && msg.name == "message";
        }
 
-       Object value;
+       static bool is(const picojson::value &json)
+       {
+               return json.contains("serverTime") && json.get("type").to_str() == "timeSync" && json.get("serverTime").is<double>();
+       }
 };
 
 class BaseJsonMessageReader
@@ -258,13 +392,36 @@ private:
 
 };
 
+
+typedef std::shared_ptr<ListMethodCall> ListMethodCallPtr;
+typedef std::shared_ptr<GetMethodCall> GetMethodCallPtr;
+typedef std::shared_ptr<SetMethodCall> SetMethodCallPtr;
+typedef std::shared_ptr<SubscribeMethodCall> SubscribeMethodCallPtr;
+typedef std::shared_ptr<UnsubscribeMethodCall> UnsubscribeMethodCallPtr;
+typedef std::shared_ptr<TimeSyncMessage> TimeSyncMessagePtr;
+
 class AmbRemoteClient: public BaseJsonMessageReader
 {
 public:
-       typedef std::function<void (std::vector<Object>)> ListCallback;
-       typedef std::function<void (Object&)> ObjectCallback;
+       typedef std::function<void (std::vector<Object::ObjectPtr>)> ListCallback;
+       typedef std::function<void (Object::ObjectPtr)> ObjectCallback;
        typedef std::function<void (bool)> SetCallback;
 
+       class Subscription
+       {
+       public:
+               Subscription(SubscribeMethodCall subscribeCall, const ObjectCallback & cb)
+                       :call(subscribeCall), callback(cb) {}
+               bool operator ==(const Subscription &rhs)
+               {
+                       return rhs.subscriptionId() == subscriptionId();
+               }
+
+               const std::string subscriptionId() const { return call.messageId; }
+               SubscribeMethodCall call;
+               AmbRemoteClient::ObjectCallback callback;
+       };
+
        AmbRemoteClient(AbstractIo* io);
 
        void list(ListCallback cb);
@@ -277,16 +434,20 @@ public:
 
        void get(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
 
-       void set(const std::string & objectName, const Object & value, SetCallback cb);
+       void set(const std::string & objectName,  Object::ObjectPtr value, SetCallback cb);
+
+       void set(const std::string & objectName, Object::ObjectPtr value, const std::string & sourceUuid, Zone::Type zone, SetCallback cb);
 
-       void set(const std::string & objectName, const Object & value, const std::string & sourceUuid, Zone::Type zone, SetCallback cb);
+       const std::string subscribe(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
 
-       void listen(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
+       void subscribe(const std::string & objectName, ObjectCallback cb);
 
-       void listen(const std::string & objectName, ObjectCallback cb);
+       void unsubscribe(const std::string & subscribeId);
 
 protected:
 
+       double correctedTime();
+
 private:
 
        void hasJsonMessage(const picojson::value & message);
@@ -295,7 +456,9 @@ private:
        std::unordered_map<std::string, ListCallback> mListCalls;
        std::unordered_map<std::string, ObjectCallback> mGetMethodCalls;
        std::unordered_map<std::string, SetCallback> mSetMethodCalls;
-       std::unordered_map<std::string, std::vector<ObjectCallback>> mSubsriptions;
+       std::unordered_map<std::string, std::vector<Subscription>> mSubscriptions;
+
+       double serverTimeOffset;
 };
 
 class AmbRemoteServer : public BaseJsonMessageReader
@@ -308,21 +471,23 @@ protected:
        /*!
         * \brief list called when a ListMessageCall was received
         */
-       virtual void list(ListMethodCall & call);
+       virtual void list(ListMethodCallPtr call);
 
        /*!
         * \brief get called when a GetMessageCall was received
         */
-       virtual void get(GetMethodCall &get);
+       virtual void get(GetMethodCallPtr get);
 
        /*!
         * \brief set called when SetMessageCall was received
         */
-       virtual void set();
+       virtual void set(SetMethodCallPtr set);
        /*!
         * \brief listen called when ListenMessageCall was received
         */
-       virtual void listen();
+       virtual void subscribe(SubscribeMethodCallPtr call);
+
+       virtual void unsubscribe(UnsubscribeMethodCallPtr call);
 
        void hasJsonMessage(const picojson::value & json);
 
index 92edc6e..01e698e 100644 (file)
 class Server : public amb::AmbRemoteServer
 {
 public:
-       Server(QLocalSocket* socketConnection): amb::AmbRemoteServer(new DomainSocket(socketConnection), nullptr) {}
+       Server(QLocalSocket* socketConnection)
+               : amb::AmbRemoteServer(new DomainSocket(socketConnection), nullptr),
+                 speed(100), engineSpeed(1999)
+       {}
 
 
        // AmbRemoteServer interface
 protected:
-       void list(amb::ListMethodCall &call)
+       void list(amb::ListMethodCallPtr call)
        {
                DebugOut(0) << "list called" << endl;
 
-               amb::Object interface1("interface1");
-               amb::Object interface2("interface2");
+               amb::Object::ObjectPtr interface1(new amb::Object("interface1"));
+               amb::Object::ObjectPtr interface2( new amb::Object("interface2"));
 
-               interface1.emplace("vehicleSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::VehicleSpeedType(100)));
-               interface1.emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(1999)));
+               interface1->emplace("vehicleSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::VehicleSpeedType(speed)));
+               interface1->emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(engineSpeed)));
 
-               interface2.emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(3099)));
+               interface2->emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(3099)));
 
-               call.objectNames.push_back(interface1);
-               call.objectNames.push_back(interface2);
-               call.success = true;
+               call->objectNames.push_back(interface1);
+               call->objectNames.push_back(interface2);
+               amb::MethodReply<amb::ListMethodCall> reply(call, true);
 
-               send(call);
+               send(reply);
        }
-       void get(amb::GetMethodCall &get)
+       void get(amb::GetMethodCallPtr get)
        {
                DebugOut(0) << "get called" << endl;
 
-               if(get.value.interfaceName == "interface1")
+               if(get->value->interfaceName == "interface1")
                {
-                       amb::Object interface1("interface1");
+                       amb::Object::ObjectPtr interface1(new amb::Object("interface1"));
 
-                       interface1.emplace("vehicleSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::VehicleSpeedType(100)));
-                       interface1.emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(1999)));
-                       get.value = interface1;
+                       interface1->emplace("vehicleSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::VehicleSpeedType(100)));
+                       interface1->emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(1999)));
+                       get->value = interface1;
+                       amb::MethodReply<amb::GetMethodCall> reply(get, true);
+                       send(reply);
                }
-               else if(get.value.interfaceName == "interface2")
+               else if(get->value->interfaceName == "interface2")
                {
-                       amb::Object interface2("interface2");
-                       interface2.emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(3099)));
-                       get.value = interface2;
+                       amb::Object::ObjectPtr interface2(new amb::Object("interface2"));
+                       interface2->emplace("engineSpeed", std::shared_ptr<AbstractPropertyType>(new VehicleProperty::EngineSpeedType(3099)));
+                       get->value = interface2;
+                       amb::MethodReply<amb::GetMethodCall> reply(get, true);
+                       send(reply);
                }
+       }
+       void set(amb::SetMethodCallPtr set)
+       {
+               if(set->value->interfaceName == "interface1")
+               {
+                       speed = set->value->at("vehicleSpeed")->value<uint16_t>();
 
-               send(get);
+                       DebugOut(0) << "Speed set to " << speed << endl;
+                       amb::MethodReply<amb::SetMethodCall> reply (set, true);
+                       send(reply);
+               }
+               else
+               {
+                       amb::MethodReply<amb::SetMethodCall> reply (set, false);
+                       send(reply);
+               }
        }
+
+       uint16_t speed;
+       uint16_t engineSpeed;
 };
 
 int main(int argc, char** argv)
index e962a7d..9cee86e 100644 (file)
 void runTest(amb::AmbRemoteClient *c)
 {
        DebugOut(0) << "calling client->list()" << endl;
-       c->list([](std::vector<amb::Object> supported)
+       c->list([](std::vector<amb::Object::ObjectPtr> supported)
        {
                DebugOut(0) << "list call reply" << endl;
                g_assert(supported.size() == 2);
        });
 
        DebugOut(0) << "calling client->get()" << endl;
-       c->get("interface1", [](amb::Object &obj)
+       c->get("interface1", [&c](amb::Object::ObjectPtr obj)
        {
                DebugOut(0) << "get call reply" << endl;
-               g_assert(obj.size() == 2);
+               g_assert(obj->size() == 2);
+
+               obj->emplace("vehicleSpeed", amb::make_shared(new VehicleProperty::VehicleSpeedType(69)));
+
+               c->set("interface1", obj, [](bool s)
+               {
+                       DebugOut(0) << "set call reply status: " << (s ? "success!" : "fail") << endl;
+                       g_assert(s);
+               });
        });
 }