Add UI handling 94/32194/12
authorAdam Malinowski <a.malinowsk2@partner.samsung.com>
Tue, 2 Dec 2014 13:52:40 +0000 (14:52 +0100)
committerAdam Malinowski <a.malinowsk2@partner.samsung.com>
Tue, 20 Jan 2015 11:59:33 +0000 (12:59 +0100)
This patch introduces user interface related stuff, implements
creating UIs and handling responses from them.

Change-Id: I8899ead4d4b6222bf6c50bb51a2703502e2f7210

src/agent/main/Agent.cpp
src/agent/main/Agent.h
src/agent/main/Response.h [new file with mode: 0644]
src/agent/ui/AskUIInterface.h [new file with mode: 0644]
src/common/types/AgentErrorMsg.cpp
src/common/types/AgentErrorMsg.h

index 477428c..89aaa04 100644 (file)
@@ -19,6 +19,9 @@
  * @brief       This file implements main class of ask user agent
  */
 
+#include <memory>
+#include <sstream>
+#include <string>
 #include <unistd.h>
 #include <utility>
 
@@ -57,28 +60,48 @@ void Agent::run() {
         std::unique_lock<std::mutex> lock(m_mutex);
         m_event.wait(lock);
 
-        while (!m_incomingRequests.empty()) {
-            Request *request = m_incomingRequests.front();
-            m_incomingRequests.pop();
-            lock.unlock();
+        while (!m_incomingRequests.empty() || !m_incomingResponses.empty()) {
+
+            if (!m_incomingRequests.empty()) {
+                Request *request = m_incomingRequests.front();
+                m_incomingRequests.pop();
+                lock.unlock();
+
+                LOGD("Request popped from queue:"
+                     " type [" << request->type() << "],"
+                     " id [" << request->id() << "],"
+                     " data length [" << request->data().size() << "]");
 
-            LOGD("Request popped from queue:"
-                 " type [" << request->type() << "],"
-                 " id [" << request->id() << "],"
-                 " data length [" << request->data().size() << "]");
+                if (request->type() == RT_Close) {
+                    delete request;
+                    m_stopFlag = 1;
+                    break;
+                }
 
-            if (request->type() == RT_Close) {
-                delete request;
-                m_stopFlag = 1;
-                break;
+                processCynaraRequest(request);
+
+                lock.lock();
             }
 
-            processCynaraRequest(request);
+            if (!m_incomingResponses.empty()) {
+                Response response = m_incomingResponses.front();
+                m_incomingResponses.pop();
+                lock.unlock();
+
+                LOGD("Response popped from queue:"
+                     " type [" << response.type() << "],"
+                     " id [" << response.id() << "]");
 
+                processUIResponse(response);
+
+                lock.lock();
+            }
+
+            lock.unlock();
+            cleanupUIThreads();
             lock.lock();
         }
 
-        //TODO: do sth here with available data from UIs
     }
 
     //TODO: dismiss all threads if possible
@@ -112,7 +135,7 @@ void Agent::processCynaraRequest(Request *request) {
             delete existingRequest->second;
             m_requests.erase(existingRequest);
             m_cynaraTalker.sendResponse(request->type(), request->id());
-            //TODO: get UI for request and dismiss or update it
+            dismissUI(request->id());
         } else {
             LOGE("Incoming request with ID: [" << request->id() << "] is being already processed");
         }
@@ -134,9 +157,84 @@ void Agent::processCynaraRequest(Request *request) {
     requestPtr.release();
 }
 
-bool Agent::startUIForRequest(Request *request UNUSED) {
-    // TODO: start UI for request
-    return false;
+void Agent::processUIResponse(const Response &response) {
+    auto requestIt = m_requests.find(response.id());
+    if (requestIt != m_requests.end()) {
+        Cynara::PluginData pluginData;
+        if (response.type() == URT_ERROR) {
+            pluginData = Translator::Agent::answerToData(Cynara::PolicyType(),
+                                                         AgentErrorMsg::Error);
+        } else if (response.type() == URT_TIMEOUT) {
+            pluginData = Translator::Agent::answerToData(Cynara::PolicyType(),
+                                                         AgentErrorMsg::Timeout);
+        } else {
+            pluginData = Translator::Agent::answerToData(
+                                            UIResponseToPolicyType(response.type()),
+                                                                   AgentErrorMsg::NoError);
+        }
+        m_cynaraTalker.sendResponse(RT_Action, requestIt->second->id(), pluginData);
+        delete requestIt->second;
+        m_requests.erase(requestIt);
+    }
+
+    dismissUI(response.id());
+}
+
+bool Agent::startUIForRequest(Request *request) {
+    auto data = Translator::Agent::dataToRequest(request->data());
+    AskUIInterfacePtr ui; // TODO: create pointer to backend
+
+    auto handler = [&](RequestId requestId, UIResponseType resultType) -> void {
+                       UIResponseHandler(requestId, resultType);
+                   };
+    bool ret = ui->start(data.client, data.user, data.privilege, request->id(), handler);
+    if (ret) {
+        m_UIs.insert(std::make_pair(request->id(), std::move(ui)));
+    }
+    return ret;
+}
+
+void Agent::UIResponseHandler(RequestId requestId, UIResponseType responseType) {
+    LOGD("UI response received: type [" << responseType << "], id [" << requestId << "]");
+
+    std::unique_lock<std::mutex> lock(m_mutex);
+    m_incomingResponses.push(Response(requestId, responseType));
+    m_event.notify_one();
+}
+
+bool Agent::cleanupUIThreads() {
+    bool ret = true;
+    for (auto it = m_UIs.begin(); it != m_UIs.end();) {
+        if (it->second->isDismissing() && it->second->dismiss()) {
+            it = m_UIs.erase(it);
+        } else {
+            ret = false;
+            ++it;
+        }
+    }
+    return ret;
+}
+
+void Agent::dismissUI(RequestId requestId) {
+    auto it = m_UIs.find(requestId);
+    if (it != m_UIs.end()) {
+        if (it->second->dismiss()) {
+            it = m_UIs.erase(it);
+        }
+    }
+}
+
+Cynara::PolicyType Agent::UIResponseToPolicyType(UIResponseType responseType) {
+    switch (responseType) {
+        case URT_YES:
+            return AskUser::SupportedTypes::Client::ALLOW_ONCE;
+        case URT_SESSION:
+            return AskUser::SupportedTypes::Client::ALLOW_PER_SESSION;
+        case URT_NO:
+            return Cynara::PredefinedPolicyType::DENY;
+        default:
+            return Cynara::PredefinedPolicyType::DENY;
+    }
 }
 
 } // namespace Agent
index 6df7c72..a1ce240 100644 (file)
 #include <map>
 #include <mutex>
 #include <queue>
+#include <types/PolicyType.h>
 
 #include <main/CynaraTalker.h>
 #include <main/Request.h>
+#include <main/Response.h>
+
+#include <ui/AskUIInterface.h>
 
 namespace AskUser {
 
@@ -49,9 +53,11 @@ private:
     CynaraTalker m_cynaraTalker;
     std::map<RequestId, Request *> m_requests;
     std::queue<Request *> m_incomingRequests;
+    std::queue<Response> m_incomingResponses;
     std::condition_variable m_event;
     std::mutex m_mutex;
     static volatile sig_atomic_t m_stopFlag;
+    std::map<RequestId, AskUIInterfacePtr> m_UIs;
 
     void init();
     void finish();
@@ -59,6 +65,13 @@ private:
     void requestHandler(Request *request);
     void processCynaraRequest(Request *request);
     bool startUIForRequest(Request *request);
+    void UIResponseHandler(RequestId requestId, UIResponseType responseType);
+
+    void processUIResponse(const Response &response);
+    bool cleanupUIThreads();
+    void dismissUI(RequestId requestId);
+
+    static Cynara::PolicyType UIResponseToPolicyType(UIResponseType responseType);
 };
 
 } // namespace Agent
diff --git a/src/agent/main/Response.h b/src/agent/main/Response.h
new file mode 100644 (file)
index 0000000..cb20353
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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        Response.h
+ * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
+ * @brief       This file declares class representing response from user interface
+ */
+
+#pragma once
+
+#include <main/Request.h>
+#include <ui/AskUIInterface.h>
+
+namespace AskUser {
+
+namespace Agent {
+
+class Response {
+public:
+    Response() = default;
+    Response(RequestId requestId, UIResponseType responseType) : m_id(requestId),
+                                                                 m_type(responseType) {}
+    ~Response() {}
+
+    RequestId id() const {
+        return m_id;
+    }
+
+    UIResponseType type() const {
+        return m_type;
+    }
+
+private:
+    RequestId m_id;
+    UIResponseType m_type;
+};
+
+} // namespace Agent
+
+} // namespace AskUser
diff --git a/src/agent/ui/AskUIInterface.h b/src/agent/ui/AskUIInterface.h
new file mode 100644 (file)
index 0000000..b78c35a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  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        AskUIInterface.h
+ * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
+ * @brief       This file contains ask user UI interface declaration.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <main/Request.h>
+
+namespace AskUser {
+
+namespace Agent {
+
+typedef enum {
+    URT_YES,
+    URT_NO,
+    URT_SESSION,
+    URT_TIMEOUT,
+    URT_ERROR
+} UIResponseType;
+
+typedef std::function<void(RequestId, UIResponseType)> UIResponseCallback;
+
+class AskUIInterface {
+public:
+    virtual ~AskUIInterface() {};
+
+    virtual bool start(const std::string &client, const std::string &user,
+                       const std::string &privilege, RequestId requestId, UIResponseCallback) = 0;
+    virtual bool setOutdated() = 0;
+    virtual bool dismiss() = 0;
+    virtual bool isDismissing() = 0;
+};
+
+typedef std::unique_ptr<AskUIInterface> AskUIInterfacePtr;
+
+} // namespace Agent
+
+} // namespace AskUser
index 983a84f..2fd5e71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2014 Samsung Electronics Co.
+ *  Copyright (c) 2014-2015 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
 namespace AskUser {
 namespace AgentErrorMsg {
 
+const std::string NoError = "";
 const std::string Error = "ERROR";
 const std::string Timeout = "TIMEOUT";
 
index 6b7dcaa..842414d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2014 Samsung Electronics Co.
+ *  Copyright (c) 2014-2015 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
 namespace AskUser {
 namespace AgentErrorMsg {
 
+extern const std::string NoError;
 extern const std::string Error;
 extern const std::string Timeout;