${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(
#include <translator/Translator.h>
#include <types/AgentErrorMsg.h>
#include <types/SupportedTypes.h>
+#include <ui/NotificationBackend.h>
#include <log/alog.h>
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);
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");
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;}
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(),
}
}
-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);
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)
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)
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});
+ }
+ }
}
}
#pragma once
+#include <cerrno>
#include <deque>
#include <functional>
#include <map>
#include <mutex>
#include <string>
+#include <thread>
#include <socket/SelectRead.h>
#include <types/RequestId.h>
{
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;
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 */
-
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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