Implementation of IPC Asynchronous Message Support.
[platform/framework/web/wrt-plugins-common.git] / src / plugins-ipc-message / ipc_message_support.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        ipc_message_support.cpp
18  * @author      Jihoon Chung (jihoon.chung@samsung.com)
19  * @version     1.0
20  * @brief       Implementation of IPC between plugins and UI Process
21  */
22 #include "ipc_message_support.h"
23
24 #include <string>
25 #include <sstream>
26 #include <WKBundle.h>
27 #include <WKString.h>
28 #include <WKType.h>
29 #include <dpl/log/log.h>
30 #include <dpl/assert.h>
31
32 static WKBundleRef s_injectedBundleRef = NULL;
33 static unsigned  int s_xWindowHandle = 0;
34
35 namespace {
36 const char* const TIZEN_GET_WINDOW_HANDLE = "tizen://getWindowHandle";
37 const char* const TIZEN_CLEAR_ALL_COOKIES = "tizen://clearAllCookies";
38
39 static std::string toString(WKStringRef str)
40 {
41     if (WKStringIsEmpty(str)) {
42         return std::string();
43     }
44     size_t size = WKStringGetMaximumUTF8CStringSize(str);
45     char buffer[size + 1];
46     WKStringGetUTF8CString(str, buffer, size + 1);
47     return buffer;
48 }
49
50 static std::string sendSyncMessage(const char* name, const char* body)
51 {
52     WKStringRef nameWKString = WKStringCreateWithUTF8CString(name);
53     WKStringRef bodyWKString = NULL;
54     if (body) {
55         bodyWKString = WKStringCreateWithUTF8CString(body);
56     }
57     WKTypeRef retWKType = NULL;
58     WKBundlePostSynchronousMessage(s_injectedBundleRef,
59                                    nameWKString,
60                                    bodyWKString,
61                                    &retWKType);
62     WKRelease(nameWKString);
63     if (bodyWKString) {
64         WKRelease(bodyWKString);
65     }
66     if (retWKType) {
67         std::string retString = toString(static_cast<WKStringRef>(retWKType));
68         WKRelease(retWKType);
69         return retString;
70     } else {
71         return std::string();
72     }
73 }
74
75 static void sendPostMessage(const char* name, const char* body)
76 {
77     WKStringRef nameWKString = WKStringCreateWithUTF8CString(name);
78     WKStringRef bodyWKString = NULL;
79     if (body) {
80         bodyWKString = WKStringCreateWithUTF8CString(body);
81     }
82     WKTypeRef retWKType = NULL;
83     WKBundlePostMessage(s_injectedBundleRef,
84                         nameWKString,
85                         bodyWKString);
86     WKRelease(nameWKString);
87     if (bodyWKString) {
88         WKRelease(bodyWKString);
89     }
90 }
91
92 static int sendAsyncMessage(const char* name, const char* body, AsyncReplyCallback replyCallback, void* data)
93 {
94     using namespace IPCMessageSupport;
95
96     int handle = AsyncConnectionManager::instance().addConnection(AsyncConnectionPtr(new AsyncConnection(replyCallback, data)));
97
98     std::string strBody = body;
99     std::stringstream ss;
100
101     ss << handle;
102     strBody = ss.str() + "_" + strBody;
103
104     sendPostMessage(name, strBody.c_str());
105
106     return handle;
107 }
108
109 } // namespace
110
111
112 namespace IPCMessageSupport {
113
114 AsyncConnectionManager::~AsyncConnectionManager()
115 {
116     m_connectionMap.clear();
117 }
118
119 AsyncConnectionManager &AsyncConnectionManager::instance()
120 {
121     static AsyncConnectionManager instance;
122
123     return instance;
124 }
125
126 int AsyncConnectionManager::addConnection(AsyncConnectionPtr connection)
127 {
128     static int latestHandle = -1;
129     int newHandle;
130
131     latestHandle++;
132     if (latestHandle < 0) latestHandle = 0;
133
134     newHandle = latestHandle;
135
136     m_connectionMap.insert(AsyncConnectionMap::value_type(newHandle, connection));
137
138     return newHandle;
139 }
140
141 bool AsyncConnectionManager::removeConnection(int handle)
142 {
143     bool ret = (m_connectionMap.erase(handle) == 1);
144
145     return ret;
146 }
147
148 AsyncConnectionPtr AsyncConnectionManager::getConnection(int handle)
149 {
150     AsyncConnectionMap::iterator iter = m_connectionMap.find(handle);
151
152     if (iter != m_connectionMap.end())
153     {
154         return iter->second;
155     }
156
157     return AsyncConnectionPtr();
158 }
159
160
161 } // namespace IPCMessageSupport
162
163
164 void IPCMessageSupport::setWKBundleRef(WKBundleRef bundleRef)
165 {
166     LogDebug("setWKBundleRef called");
167     s_injectedBundleRef = bundleRef;
168 }
169
170 void IPCMessageSupport::setXwindowHandle(unsigned int handle)
171 {
172     LogDebug("setXwindowHandle called");
173     s_xWindowHandle = handle;
174 }
175
176 const char* IPCMessageSupport::sendMessageToUiProcess(
177     const char* name,
178     const char* body)
179 {
180     LogDebug("sendMessageToUiProcess called");
181     if (s_injectedBundleRef == NULL) {
182         LogError("UI Process information isn't set");
183         return NULL;
184     }
185     LogDebug("name = [" << name << "]");
186     if (body) {
187         LogDebug("body = [" << body << "]");
188     }
189
190     if (!name) {
191         return NULL;
192     }
193
194     // tizen://getWindowHandle
195     if (!strcmp(name, TIZEN_GET_WINDOW_HANDLE)) {
196         if (s_xWindowHandle == 0) {
197             return NULL;
198         } else {
199             std::stringstream ss;
200             ss << s_xWindowHandle;
201             std::string ret  = ss.str();
202             return strdup(ret.c_str());
203         }
204     }
205
206     // tizen://clearAllCookies
207     if (!strcmp(name, TIZEN_CLEAR_ALL_COOKIES)) {
208         sendPostMessage(name, body);
209         return NULL;
210     }
211
212     return NULL;
213 }
214
215 int IPCMessageSupport::sendAsyncMessageToUiProcess(const char* name, const char* body, AsyncReplyCallback replyCallback, void* data)
216 {
217     LogDebug("sendAsyncMessageToUiProcess called");
218
219     if (s_injectedBundleRef == NULL)
220     {
221         LogError("UI Process information isn't set");
222         return -1;
223     }
224
225     if (name == NULL)
226     {
227         LogError("msg name is null!");
228         return -1;
229     }
230
231     if (body == NULL)
232     {
233         body = "";
234     }
235
236     LogDebug("name = [" << name << "]");
237     LogDebug("body = [" << body << "]");
238
239     return sendAsyncMessage(name, body, replyCallback, data);
240 }
241
242 void* IPCMessageSupport::ignoreAsyncMessageReply(int handle)
243 {
244     LogDebug("ignoreAsyncMessageReply called");
245
246     AsyncConnectionPtr connection = AsyncConnectionManager::instance().getConnection(handle);
247
248     if (!connection)
249     {
250         return NULL;
251     }
252
253     AsyncConnectionManager::instance().removeConnection(handle);
254
255     return connection->data;
256 }
257
258 void IPCMessageSupport::replyAsyncMessageToWebProcess(Ewk_Context* ewkContext, int handle, const char* body)
259 {
260     LogDebug("replyAsyncMessageToWebProcess called");
261
262     if (ewkContext == NULL)
263     {
264         return;
265     }
266
267     std::string strBody = (body) ? (body) : "";
268     std::stringstream ss;
269     ss << handle;
270
271     strBody = ss.str() + "_" + strBody;
272
273     ewk_context_message_post_to_injected_bundle(ewkContext, REPLY_ASYNC, strBody.c_str());
274 }