[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / network-performance-client.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
18 // CLASS HEADER
19 #include <dali/internal/network/common/network-performance-client.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdio.h>
23 #include <iostream>
24 #include <string>
25
26 // INTERNAL INCLUDES
27 #include <dali/internal/network/common/automation.h>
28 #include <dali/internal/network/common/network-performance-protocol.h>
29 #include <dali/internal/network/common/socket-interface.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace
38 {
39 const float MICROSECONDS_TO_SECOND = 1e-6;
40 const char  UNKNOWN_CMD[]          = "Command or parameter invalid, type help for list of commands\n";
41
42 /**
43  * helper class to store data along with the automation callback.
44  */
45 class AutomationCallback : public CallbackBase
46 {
47 public:
48   /**
49    * instead of using templates, or having different callback classes for each callback
50    * we use a command id that decides which static function to call on the Automation class.
51    */
52   enum CommandId
53   {
54     UNKNOWN_COMMAND,
55     SET_PROPERTY,
56     CUSTOM_COMMAND,
57     DUMP_SCENE
58   };
59
60   AutomationCallback(unsigned int clientId, ClientSendDataInterface& sendDataInterface)
61   : CallbackBase(reinterpret_cast<void*>(this),
62                  NULL, // we get the dispatcher to call function directly
63                  reinterpret_cast<CallbackBase::Dispatcher>(&AutomationCallback::Dispatcher)),
64     mSendDataInterface(sendDataInterface),
65     mCommandId(UNKNOWN_COMMAND),
66     mClientId(clientId)
67   {
68   }
69
70   void AssignSetPropertyCommand(std::string setPropertyCommand)
71   {
72     mCommandId     = SET_PROPERTY;
73     mCommandString = setPropertyCommand;
74   }
75
76   void AssignDumpSceneCommand()
77   {
78     mCommandId = DUMP_SCENE;
79   }
80
81   void AssignCustomCommand(std::string&& customCommand)
82   {
83     mCommandId     = CUSTOM_COMMAND;
84     mCommandString = std::move(customCommand);
85   }
86
87   void RunCallback()
88   {
89     switch(mCommandId)
90     {
91       case SET_PROPERTY:
92       {
93         Automation::SetProperty(mCommandString);
94         break;
95       }
96       case DUMP_SCENE:
97       {
98         Automation::DumpScene(mClientId, &mSendDataInterface);
99         break;
100       }
101       case CUSTOM_COMMAND:
102       {
103         Automation::SetCustomCommand(mCommandString);
104         break;
105       }
106       default:
107       {
108         DALI_ASSERT_DEBUG(0 && "Unknown command");
109         break;
110       }
111     }
112   }
113   static void Dispatcher(CallbackBase& base)
114   {
115     AutomationCallback& automationCallback(static_cast<AutomationCallback&>(base));
116     automationCallback.RunCallback();
117   }
118
119 private:
120   std::string              mCommandString;     ///< command string for property or custom command
121   ClientSendDataInterface& mSendDataInterface; ///< Abstract client send data interface
122   CommandId                mCommandId;         ///< command id
123   const unsigned int       mClientId;          ///< client id
124 };
125
126 /**
127  * @brief Helper to ensure the AutomationCallback method we want is called in the main thread
128  */
129 template<typename T>
130 void TriggerOnMainThread(unsigned int clientId, ClientSendDataInterface& sendDataInterface, T&& lambda)
131 {
132   // this needs to be run on the main thread, use the trigger event....
133   AutomationCallback* callback = new AutomationCallback(clientId, sendDataInterface);
134   lambda(callback);
135   sendDataInterface.TriggerMainThreadAutomation(callback);
136 }
137
138 } // unnamed namespace
139
140 NetworkPerformanceClient::NetworkPerformanceClient(pthread_t*               thread,
141                                                    SocketInterface*         socket,
142                                                    unsigned int             clientId,
143                                                    ClientSendDataInterface& sendDataInterface,
144                                                    SocketFactoryInterface&  socketFactory)
145 : mThread(thread),
146   mSocket(socket),
147   mMarkerBitmask(PerformanceMarker::FILTERING_DISABLED),
148   mSendDataInterface(sendDataInterface),
149   mSocketFactoryInterface(socketFactory),
150   mClientId(clientId),
151   mConsoleClient(false)
152 {
153 }
154
155 NetworkPerformanceClient::~NetworkPerformanceClient()
156 {
157   if(mSocket->SocketIsOpen())
158   {
159     mSocket->CloseSocket();
160   }
161   mSocketFactoryInterface.DestroySocket(mSocket);
162 }
163
164 unsigned int NetworkPerformanceClient::GetId() const
165 {
166   return mClientId;
167 }
168
169 SocketInterface& NetworkPerformanceClient::GetSocket()
170 {
171   return *mSocket;
172 }
173
174 bool NetworkPerformanceClient::WriteSocket(const void* buffer, unsigned int bufferSizeInBytes)
175 {
176   return mSocket->Write(buffer, bufferSizeInBytes);
177 }
178
179 bool NetworkPerformanceClient::TransmitMarker(const PerformanceMarker& marker, const char* const description)
180 {
181   if(!marker.IsFilterEnabled(mMarkerBitmask))
182   {
183     return true;
184   }
185   if(mConsoleClient)
186   {
187     // write out the time stamp
188     char*  buffer;
189     double usec   = marker.GetTimeStamp().microseconds;
190     int    size   = asprintf(&buffer, "%.6f (seconds), %s\n", usec * MICROSECONDS_TO_SECOND, description);
191     auto   retVal = mSocket->Write(buffer, size);
192     free(buffer);
193     return retVal;
194   }
195
196   // todo serialize the data
197   return false;
198 }
199
200 void NetworkPerformanceClient::ExitSelect()
201 {
202   mSocket->ExitSelect();
203 }
204
205 pthread_t* NetworkPerformanceClient::GetThread()
206 {
207   return mThread;
208 }
209
210 void NetworkPerformanceClient::ProcessCommand(char* buffer, unsigned int bufferSizeInBytes)
211 {
212   // if connected via console, then strip off the carriage return, and switch to console mode
213   if(buffer[bufferSizeInBytes - 1] == '\n')
214   {
215     buffer[bufferSizeInBytes - 1] = 0;
216     mConsoleClient                = true;
217   }
218   unsigned int                   param(0);
219   std::string                    stringParam;
220   PerformanceProtocol::CommandId commandId(PerformanceProtocol::UNKNOWN_COMMAND);
221
222   bool ok = PerformanceProtocol::GetCommandId(buffer, bufferSizeInBytes, commandId, param, stringParam);
223   if(!ok)
224   {
225     WriteSocket(UNKNOWN_CMD, sizeof(UNKNOWN_CMD));
226     return;
227   }
228   std::string response;
229
230   switch(commandId)
231   {
232     case PerformanceProtocol::HELP_MESSAGE:
233     {
234       response = PerformanceProtocol::GetHelpMessage();
235       break;
236     }
237
238     case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
239     {
240       mMarkerBitmask = static_cast<PerformanceMarker::MarkerFilter>(param);
241       response       = "enable time marker ";
242       break;
243     }
244
245     case PerformanceProtocol::DUMP_SCENE_GRAPH:
246     {
247       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback) { callback->AssignDumpSceneCommand(); });
248       break;
249     }
250
251     case PerformanceProtocol::SET_PROPERTIES:
252     {
253       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback) { callback->AssignSetPropertyCommand(stringParam); });
254       response = "Completed";
255       break;
256     }
257
258     case PerformanceProtocol::CUSTOM_COMMAND:
259     {
260       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback) { callback->AssignCustomCommand(std::move(stringParam)); });
261       response = "Completed";
262       break;
263     }
264
265     case PerformanceProtocol::LIST_METRICS_AVAILABLE:
266     case PerformanceProtocol::ENABLE_METRIC:
267     case PerformanceProtocol::DISABLE_METRIC:
268     {
269       response = "Metrics currently not supported";
270       break;
271     }
272     default:
273     {
274       response = UNKNOWN_CMD;
275       break;
276     }
277   }
278   if(!response.empty())
279   {
280     // add a carriage return for console clients
281     if(mConsoleClient)
282     {
283       response += "\n";
284     }
285     WriteSocket(response.c_str(), response.length());
286   }
287 }
288
289 } // namespace Adaptor
290
291 } // namespace Internal
292
293 } // namespace Dali