Adjust notification talker to work as backend 54/72854/8
authorZofia Abramowska <z.abramowska@samsung.com>
Thu, 2 Jun 2016 10:42:46 +0000 (12:42 +0200)
committerOskar Świtalski <o.switalski@samsung.com>
Fri, 10 Jun 2016 15:48:33 +0000 (17:48 +0200)
Change-Id: I5130aab7901c12944bb41e91a359965e318d23ce

src/agent/CMakeLists.txt
src/agent/main/Agent.cpp
src/agent/main/NotificationTalker.cpp
src/agent/main/NotificationTalker.h
src/agent/ui/NotificationBackend.cpp [new file with mode: 0644]
src/agent/ui/NotificationBackend.h [new file with mode: 0644]

index fa184c5..11208b3 100644 (file)
@@ -32,6 +32,7 @@ SET(ASKUSER_SOURCES
     ${ASKUSER_AGENT_PATH}/main/CynaraTalker.cpp
     ${ASKUSER_AGENT_PATH}/main/main.cpp
     ${ASKUSER_AGENT_PATH}/main/NotificationTalker.cpp
+    ${ASKUSER_AGENT_PATH}/ui/NotificationBackend.cpp
     )
 
 INCLUDE_DIRECTORIES(
index 2fcad97..6b0e8bd 100644 (file)
@@ -31,6 +31,7 @@
 #include <translator/Translator.h>
 #include <types/AgentErrorMsg.h>
 #include <types/SupportedTypes.h>
+#include <ui/NotificationBackend.h>
 
 #include <log/alog.h>
 
@@ -205,7 +206,8 @@ void Agent::processUIResponse(const Response &response) {
 
 bool Agent::startUIForRequest(Request *request) {
     auto data = Translator::Agent::dataToRequest(request->data());
-    AskUIInterfacePtr ui(nullptr);
+
+    AskUIInterfacePtr ui(new NotificationBackend());
 
     auto handler = [&](RequestId requestId, UIResponseType resultType) -> void {
                        UIResponseHandler(requestId, resultType);
index 57d1f33..725a27a 100644 (file)
@@ -37,15 +37,36 @@ namespace AskUser {
 
 namespace Agent {
 
-NotificationTalker::NotificationTalker()
+NotificationTalker::NotificationTalker() : m_failed(true), m_stopflag(false)
 {
-    m_stopflag = false;
     m_select.setTimeout(100);
-    m_sockfd = Socket::listen(Path::getSocketPath().c_str());
+    try {
+        m_sockfd = Socket::listen(Path::getSocketPath());
+        m_thread = std::thread(&NotificationTalker::run, this);
+        m_failed = false;
+    } catch (const Exception &e) {
+        setErrorMsg(e.what());
+    } catch (const std::exception &e) {
+        setErrorMsg(std::string("caught std::exception: ") + e.what());
+    } catch (...) {
+        setErrorMsg("caught unknown exception");
+    }
+}
+
+void NotificationTalker::setErrorMsg(std::string s)
+{
+    m_errorMsg = std::move(s);
 }
 
 void NotificationTalker::parseRequest(RequestType type, NotificationRequest request)
 {
+    std::lock_guard<std::mutex> lock(m_bfLock);
+
+    if (!m_responseHandler) {
+        ALOGE("Response handler not set!");
+        return;
+    }
+
     switch (type) {
     case RequestType::RT_Close:
         ALOGD("Close service");
@@ -66,8 +87,6 @@ void NotificationTalker::parseRequest(RequestType type, NotificationRequest requ
 
 void NotificationTalker::addRequest(NotificationRequest &&request)
 {
-    std::lock_guard<std::mutex> lock(m_mutex);
-
     auto &queue = m_requests[request.data.user];
     auto it = std::find_if(queue.begin(), queue.end(),
             [&request](const NotificationRequest &req){return req.id == request.id;}
@@ -82,8 +101,6 @@ void NotificationTalker::addRequest(NotificationRequest &&request)
 
 void NotificationTalker::removeRequest(RequestId id)
 {
-    std::lock_guard<std::mutex> lock(m_mutex);
-
     for (auto &pair : m_requests) {
         auto &queue = std::get<1>(pair);
         auto it = std::find_if(queue.begin(), queue.end(),
@@ -104,15 +121,13 @@ void NotificationTalker::removeRequest(RequestId id)
     }
 }
 
-void NotificationTalker::setResponseHandler(ResponseHandler responseHandler)
-{
-    m_responseHandler = responseHandler;
-}
-
 void NotificationTalker::stop()
 {
     m_stopflag = true;
+}
 
+void NotificationTalker::clear()
+{
     for (auto& pair : m_fdStatus) {
         int fd = std::get<0>(pair);
         Socket::close(fd);
@@ -128,12 +143,9 @@ void NotificationTalker::stop()
 
 NotificationTalker::~NotificationTalker()
 {
-    for (auto& pair : m_fdStatus) {
-        int fd = std::get<0>(pair);
-        Socket::close(fd);
-    }
-
-    Socket::close(m_sockfd);
+    stop();
+    clear();
+    m_thread.join();
 }
 
 void NotificationTalker::sendRequest(int fd, const NotificationRequest &request)
@@ -265,6 +277,8 @@ void NotificationTalker::run()
     try {
         ALOGD("Notification loop started");
         while (!m_stopflag) {
+            std::lock_guard<std::mutex> lock(m_bfLock);
+
             m_select.add(m_sockfd);
 
             for (auto pair : m_userToFd)
@@ -272,35 +286,41 @@ void NotificationTalker::run()
 
             int rv = m_select.exec();
 
-            if (m_stopflag)
+            if (m_stopflag) {
+                clear();
                 break;
+            }
 
             if (rv) {
                 newConnection(rv);
                 recvResponses(rv);
-            } else {
-                // timeout
             }
 
-            /* lock_guard */
-            {
-                std::lock_guard<std::mutex> lock(m_mutex);
-                for (auto pair : m_fdStatus ) {
-                    int fd = std::get<0>(pair);
-                    bool b = std::get<1>(pair);
-                    auto &queue = m_requests[m_fdToUser[fd]];
-                    if (b && !queue.empty()) {
-                        NotificationRequest request = queue.front();
-                        sendRequest(fd, request);
-                    }
+            for (auto pair : m_fdStatus ) {
+                int fd = std::get<0>(pair);
+                bool b = std::get<1>(pair);
+                auto &queue = m_requests[m_fdToUser[fd]];
+                if (b && !queue.empty()) {
+                    NotificationRequest request = queue.front();
+                    sendRequest(fd, request);
                 }
-            } /* lock_guard */
+            }
         }
         ALOGD("NotificationTalker loop ended");
     } catch (const std::exception &e) {
-        ALOGE("NotificationTalker: " << e.what());
+        setErrorMsg(e.what());
+        m_failed = true;
     } catch (...) {
-        ALOGE("NotificationTalker: unknown error");
+        setErrorMsg("unknown error");
+        m_failed = true;
+    }
+
+    if (m_failed && m_responseHandler) {
+        for (auto &queuePair : m_requests) {
+            for (auto &request : std::get<1>(queuePair)) {
+                m_responseHandler({request.id, NResponseType::Error});
+            }
+        }
     }
 }
 
index a6c77e7..1bed8b3 100644 (file)
 
 #pragma once
 
+#include <cerrno>
 #include <deque>
 #include <functional>
 #include <map>
 #include <mutex>
 #include <string>
+#include <thread>
 
 #include <socket/SelectRead.h>
 #include <types/RequestId.h>
@@ -51,15 +53,33 @@ class NotificationTalker
 {
 public:
     NotificationTalker();
-
+    bool isFailed() { return m_failed; }
+    std::string getErrorMsg() { return m_errorMsg; }
+    void setResponseHandler(ResponseHandler responseHandler)
+    {
+        m_responseHandler = responseHandler;
+    }
     void parseRequest(RequestType type, NotificationRequest request);
-    void run();
-    void setResponseHandler(ResponseHandler responseHandler);
     virtual void stop();
 
-    ~NotificationTalker();
+    virtual ~NotificationTalker();
 
 protected:
+    void setErrorMsg(std::string s);
+    void run();
+    void parseResponse(NotificationResponse response, int fd);
+    void recvResponses(int &rv);
+
+    void newConnection(int &rv);
+    void remove(int fd);
+
+    void clear();
+
+    virtual void addRequest(NotificationRequest &&request);
+    virtual void removeRequest(RequestId id);
+    virtual void sendRequest(int fd, const NotificationRequest &request);
+    virtual void sendDismiss(int fd);
+
     ResponseHandler m_responseHandler;
 
     UserToFdMap m_userToFd;
@@ -67,25 +87,16 @@ protected:
     FdStatus m_fdStatus;
     Socket::SelectRead m_select;
     int m_sockfd = 0;
+    bool m_failed;
+    std::string m_errorMsg;
 
     RequestsQueue m_requests;
-    std::mutex m_mutex;
+    std::mutex m_bfLock;
 
+    std::thread m_thread;
     bool m_stopflag;
-
-    void parseResponse(NotificationResponse response, int fd);
-    void recvResponses(int &rv);
-
-    void newConnection(int &rv);
-    void remove(int fd);
-
-    virtual void addRequest(NotificationRequest &&request);
-    virtual void removeRequest(RequestId id);
-    virtual void sendRequest(int fd, const NotificationRequest &request);
-    virtual void sendDismiss(int fd);
 };
 
 } /* namespace Agent */
 
 } /* namespace AskUser */
-
diff --git a/src/agent/ui/NotificationBackend.cpp b/src/agent/ui/NotificationBackend.cpp
new file mode 100644 (file)
index 0000000..09f01f2
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+/**
+ * @file        NotificationBackend.cpp
+ * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @brief       This file contains notification backend definition.
+ */
+
+#include <stdexcept>
+#include <log/alog.h>
+
+#include "NotificationBackend.h"
+
+namespace AskUser {
+
+namespace Agent {
+
+NotificationTalker NotificationBackend::m_notiTalker;
+std::map<RequestId, NotificationBackend *> NotificationBackend::m_idToInstance;
+std::mutex NotificationBackend::m_instanceGuard;
+
+NotificationBackend::NotificationBackend() : m_id(-1), m_isDismissing(false)
+{
+    if (m_notiTalker.isFailed()) {
+        ALOGE("NotificationTalker failed beacause: " << m_notiTalker.getErrorMsg());
+        throw std::runtime_error("Backend failed");
+    }
+}
+
+bool NotificationBackend::start(const std::string &client, const std::string &user,
+                                const std::string &privilege, RequestId requestId,
+                                UIResponseCallback callback)
+{
+    m_idToInstance[requestId] = this;
+    m_id = requestId;
+    m_cb = callback;
+
+    if (m_notiTalker.isFailed()) {
+        ALOGE("NotificationTalker failed beacause: " << m_notiTalker.getErrorMsg());
+        throw std::runtime_error("Backend failed");
+    }
+
+    m_notiTalker.setResponseHandler(&NotificationBackend::responseCb);
+    m_notiTalker.parseRequest(RequestType::RT_Action,
+                              NotificationRequest(requestId, client, user, privilege));
+    return true;
+}
+
+void NotificationBackend::responseCb(NotificationResponse response)
+{
+    std::lock_guard<std::mutex> lock(m_instanceGuard);
+    auto it = m_idToInstance.find(response.id);
+    if (it == m_idToInstance.end()) {
+        ALOGW("Instance for this request does not exist anymore");
+        return;
+    }
+    UIResponseType type;
+    switch(response.response) {
+    case NResponseType::Allow:
+        type = UIResponseType::URT_YES_LIFE;
+        break;
+    case NResponseType::Deny:
+        type = UIResponseType::URT_NO_ONCE;
+        break;
+    case NResponseType::Never:
+        type = UIResponseType::URT_NO_LIFE;
+        break;
+    case NResponseType::Error:
+        type = UIResponseType::URT_ERROR;
+        break;
+    case NResponseType::None:
+        type = UIResponseType::URT_TIMEOUT;
+        break;
+    }
+    it->second->m_cb(response.id, type);
+}
+
+bool NotificationBackend::setOutdated()
+{
+    return true;
+}
+
+bool NotificationBackend::dismiss()
+{
+    m_notiTalker.parseRequest(RequestType::RT_Cancel, NotificationRequest(m_id));
+    return true;
+}
+
+bool NotificationBackend::isDismissing() const
+{
+    return m_isDismissing;
+}
+
+NotificationBackend::~NotificationBackend()
+{
+    std::lock_guard<std::mutex> lock(m_instanceGuard);
+    m_idToInstance.erase(m_id);
+}
+
+} //namespace Agent
+
+} //namespace AskUser
diff --git a/src/agent/ui/NotificationBackend.h b/src/agent/ui/NotificationBackend.h
new file mode 100644 (file)
index 0000000..6256bf8
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+/**
+ * @file        NotificationBackend.h
+ * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @brief       This file contains notification backend declaration.
+ */
+
+#pragma once
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <main/Request.h>
+#include <main/NotificationTalker.h>
+#include <ui/AskUIInterface.h>
+
+#include <types/NotificationResponse.h>
+
+namespace AskUser {
+
+namespace Agent {
+
+class NotificationBackend : public AskUIInterface {
+public:
+    NotificationBackend();
+    virtual ~NotificationBackend();
+
+    virtual bool start(const std::string &client, const std::string &user,
+                       const std::string &privilege, RequestId requestId, UIResponseCallback);
+    virtual bool setOutdated();
+    virtual bool dismiss();
+    virtual bool isDismissing() const;
+
+private:
+    static void responseCb(NotificationResponse response);
+    static NotificationTalker m_notiTalker;
+    static std::map<RequestId, NotificationBackend *> m_idToInstance;
+    static std::mutex m_instanceGuard;
+
+    RequestId m_id;
+    UIResponseCallback m_cb;
+    bool m_isDismissing;
+};
+
+    typedef std::unique_ptr<NotificationBackend> NotificationBackendPtr;
+} // namespace Agent
+
+} // namespace AskUser