(Network) Add a custom_command option
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / network-performance-client.cpp
1 /*
2  * Copyright (c) 2022 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
136   // create a trigger event that automatically deletes itself after the callback has run in the main thread
137   TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
138
139   // asynchronous call, the call back will be run sometime later on the main thread
140   interface->Trigger();
141 }
142
143 } // unnamed namespace
144
145 NetworkPerformanceClient::NetworkPerformanceClient(pthread_t*               thread,
146                                                    SocketInterface*         socket,
147                                                    unsigned int             clientId,
148                                                    ClientSendDataInterface& sendDataInterface,
149                                                    SocketFactoryInterface&  socketFactory)
150 : mThread(thread),
151   mSocket(socket),
152   mMarkerBitmask(PerformanceMarker::FILTERING_DISABLED),
153   mSendDataInterface(sendDataInterface),
154   mSocketFactoryInterface(socketFactory),
155   mClientId(clientId),
156   mConsoleClient(false)
157 {
158 }
159
160 NetworkPerformanceClient::~NetworkPerformanceClient()
161 {
162   if(mSocket->SocketIsOpen())
163   {
164     mSocket->CloseSocket();
165   }
166   mSocketFactoryInterface.DestroySocket(mSocket);
167 }
168
169 unsigned int NetworkPerformanceClient::GetId() const
170 {
171   return mClientId;
172 }
173
174 SocketInterface& NetworkPerformanceClient::GetSocket()
175 {
176   return *mSocket;
177 }
178
179 bool NetworkPerformanceClient::WriteSocket(const void* buffer, unsigned int bufferSizeInBytes)
180 {
181   return mSocket->Write(buffer, bufferSizeInBytes);
182 }
183
184 bool NetworkPerformanceClient::TransmitMarker(const PerformanceMarker& marker, const char* const description)
185 {
186   if(!marker.IsFilterEnabled(mMarkerBitmask))
187   {
188     return true;
189   }
190   if(mConsoleClient)
191   {
192     // write out the time stamp
193     char   buffer[64];
194     double usec = marker.GetTimeStamp().microseconds;
195     int    size = snprintf(buffer, sizeof(buffer), "%.6f (seconds), %s\n", usec * MICROSECONDS_TO_SECOND, description);
196
197     return mSocket->Write(buffer, size);
198   }
199
200   // todo serialize the data
201   return false;
202 }
203
204 void NetworkPerformanceClient::ExitSelect()
205 {
206   mSocket->ExitSelect();
207 }
208
209 pthread_t* NetworkPerformanceClient::GetThread()
210 {
211   return mThread;
212 }
213
214 void NetworkPerformanceClient::ProcessCommand(char* buffer, unsigned int bufferSizeInBytes)
215 {
216   // if connected via console, then strip off the carriage return, and switch to console mode
217   if(buffer[bufferSizeInBytes - 1] == '\n')
218   {
219     buffer[bufferSizeInBytes - 1] = 0;
220     mConsoleClient                = true;
221   }
222   unsigned int                   param(0);
223   std::string                    stringParam;
224   PerformanceProtocol::CommandId commandId(PerformanceProtocol::UNKNOWN_COMMAND);
225
226   bool ok = PerformanceProtocol::GetCommandId(buffer, bufferSizeInBytes, commandId, param, stringParam);
227   if(!ok)
228   {
229     WriteSocket(UNKNOWN_CMD, sizeof(UNKNOWN_CMD));
230     return;
231   }
232   std::string response;
233
234   switch(commandId)
235   {
236     case PerformanceProtocol::HELP_MESSAGE:
237     {
238       response = PerformanceProtocol::GetHelpMessage();
239       break;
240     }
241
242     case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
243     {
244       mMarkerBitmask = static_cast<PerformanceMarker::MarkerFilter>(param);
245       response       = "enable time marker ";
246       break;
247     }
248
249     case PerformanceProtocol::DUMP_SCENE_GRAPH:
250     {
251       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignDumpSceneCommand();});
252       break;
253     }
254
255     case PerformanceProtocol::SET_PROPERTIES:
256     {
257       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignSetPropertyCommand(stringParam);});
258       response = "Completed";
259       break;
260     }
261
262     case PerformanceProtocol::CUSTOM_COMMAND:
263     {
264       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignCustomCommand(std::move(stringParam));});
265       response = "Completed";
266       break;
267     }
268
269     case PerformanceProtocol::LIST_METRICS_AVAILABLE:
270     case PerformanceProtocol::ENABLE_METRIC:
271     case PerformanceProtocol::DISABLE_METRIC:
272     {
273       response = "Metrics currently not supported";
274       break;
275     }
276     default:
277     {
278       response = UNKNOWN_CMD;
279       break;
280     }
281   }
282   if(!response.empty())
283   {
284     // add a carriage return for console clients
285     if(mConsoleClient)
286     {
287       response += "\n";
288     }
289     WriteSocket(response.c_str(), response.length());
290   }
291 }
292
293 } // namespace Adaptor
294
295 } // namespace Internal
296
297 } // namespace Dali