1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17 #include "CommandLineInterface.h"
18
19 #include <chrono>
20 #include <regex>
21
22 #include "CommandLine.h"
23 #include "CommandLineFactory.h"
24 #include "ModelManager.h"
25 #include "PreviewerEngineLog.h"
26 #include "VirtualScreen.h"
27 #include "CommandParser.h"
28
29 const std::string CommandLineInterface::COMMAND_VERSION = "1.0.1";
30 bool CommandLineInterface::isFirstWsSend = true;
31 bool CommandLineInterface::isPipeConnected = false;
CommandLineInterface()32 CommandLineInterface::CommandLineInterface() : socket(nullptr) {}
33
~CommandLineInterface()34 CommandLineInterface::~CommandLineInterface() {}
35
InitPipe(const std::string name)36 void CommandLineInterface::InitPipe(const std::string name)
37 {
38 if (socket != nullptr) {
39 socket.reset();
40 ELOG("CommandLineInterface::InitPipe socket is not null");
41 }
42
43 socket = std::make_unique<LocalSocket>();
44 if (socket == nullptr) {
45 FLOG("CommandLineInterface::Connect socket memory allocation failed!");
46 }
47
48 if (!socket->ConnectToServer(socket->GetCommandPipeName(name), LocalSocket::READ_WRITE)) {
49 FLOG("CommandLineInterface command pipe connect failed");
50 }
51 isPipeConnected = true;
52 }
53
GetInstance()54 CommandLineInterface& CommandLineInterface::GetInstance()
55 {
56 static CommandLineInterface instance; /* NOLINT */
57 return instance;
58 }
59
SendJsonData(const Json2::Value & value)60 void CommandLineInterface::SendJsonData(const Json2::Value& value)
61 {
62 *(GetInstance().socket) << value.ToStyledString();
63 }
64
SendJSHeapMemory(size_t total,size_t alloc,size_t peak) const65 void CommandLineInterface::SendJSHeapMemory(size_t total, size_t alloc, size_t peak) const
66 {
67 Json2::Value result = JsonReader::CreateObject();
68 result.Add("version", COMMAND_VERSION.c_str());
69 result.Add("property", "memoryUsage");
70 Json2::Value memory = JsonReader::CreateObject();
71 memory.Add("totalBytes", static_cast<double>(total));
72 memory.Add("allocBytes", static_cast<double>(alloc));
73 memory.Add("peakAllocBytes", static_cast<double>(peak));
74 result.Add("result", memory);
75 if (socket == nullptr) {
76 ELOG("CommandLineInterface::SendJSHeapMemory socket is null");
77 return;
78 }
79 *socket << result.ToStyledString();
80 }
81
SendWebsocketStartupSignal() const82 void CommandLineInterface::SendWebsocketStartupSignal() const
83 {
84 Json2::Value result = JsonReader::CreateObject();
85 Json2::Value args = JsonReader::CreateObject();
86 result.Add("MessageType", "imageWebsocket");
87 args.Add("port", VirtualScreen::webSocketPort.c_str());
88 result.Add("args", args);
89 *socket << result.ToStyledString();
90 }
91
ProcessCommand() const92 void CommandLineInterface::ProcessCommand() const
93 {
94 std::string message; /* NOLINT */
95 if (socket == nullptr) {
96 ELOG("CommandLineInterface::ProcessCommand socket is null");
97 return;
98 }
99 if (isPipeConnected && VirtualScreen::isWebSocketListening && isFirstWsSend) {
100 isFirstWsSend = false;
101 SendWebsocketStartupSignal();
102 }
103 *socket >> message;
104 if (message.empty()) {
105 return;
106 }
107
108 ProcessCommandMessage(message);
109 }
110
ProcessCommandMessage(std::string message) const111 void CommandLineInterface::ProcessCommandMessage(std::string message) const
112 {
113 ILOG("***cmd*** message:%s", message.c_str());
114 Json2::Value jsonData = JsonReader::ParseJsonData2(message);
115 std::string errors; /* NOLINT */
116 bool parsingSuccessful = jsonData.IsNull() ? false : true;
117 if (!parsingSuccessful) {
118 errors = JsonReader::GetErrorPtr();
119 }
120
121 if (!ProcessCommandValidate(parsingSuccessful, jsonData, errors)) {
122 return;
123 }
124
125 CommandLine::CommandType type = GetCommandType(jsonData["type"].AsString());
126 if (type == CommandLine::CommandType::INVALID) {
127 return;
128 }
129
130 std::string command = jsonData["command"].AsString();
131 if (CommandParser::GetInstance().IsStaticCard() && IsStaticIgnoreCmd(command)) {
132 return;
133 }
134 Json2::Value val = jsonData["args"];
135 std::unique_ptr<CommandLine> commandLine =
136 CommandLineFactory::CreateCommandLine(command, type, val, *socket);
137 if (commandLine == nullptr) {
138 ELOG("Unsupported command");
139 return;
140 }
141 commandLine->CheckAndRun();
142 }
143
ProcessCommandValidate(bool parsingSuccessful,const Json2::Value & jsonData,const std::string & errors) const144 bool CommandLineInterface::ProcessCommandValidate(bool parsingSuccessful,
145 const Json2::Value& jsonData,
146 const std::string& errors) const
147 {
148 if (!parsingSuccessful) {
149 ELOG("Failed to parse the JSON, errors: %s", errors.c_str());
150 return false;
151 }
152
153 if (!jsonData.IsObject()) {
154 ELOG("Command is not a object!");
155 return false;
156 }
157
158 if (!jsonData.IsMember("type") || !jsonData.IsMember("command") || !jsonData.IsMember("version")) {
159 ELOG("Command error!");
160 return false;
161 }
162
163 if (!regex_match(jsonData["version"].AsString(),
164 std::regex("(([0-9]|([1-9]([0-9]*))).){2}([0-9]|([1-9]([0-9]*)))"))) {
165 ELOG("Invalid command version!");
166 return false;
167 }
168 return true;
169 }
170
GetCommandType(std::string name) const171 CommandLine::CommandType CommandLineInterface::GetCommandType(std::string name) const
172 {
173 CommandLine::CommandType type = CommandLine::CommandType::INVALID;
174 if (name == "set") {
175 type = CommandLine::CommandType::SET;
176 } else if (name == "get") {
177 type = CommandLine::CommandType::GET;
178 } else if (name == "action") {
179 type = CommandLine::CommandType::ACTION;
180 } else {
181 ELOG("Command type invalid!");
182 }
183 return type;
184 }
185
ApplyConfig(const Json2::Value & val) const186 void CommandLineInterface::ApplyConfig(const Json2::Value& val) const
187 {
188 const std::string set("setting");
189 if (val.IsMember(set.c_str())) {
190 Json2::Value versionMembers = val[set];
191 if (!versionMembers.IsObject()) {
192 return;
193 }
194
195 Json2::Value::Members versions = versionMembers.GetMemberNames();
196
197 for (Json2::Value::Members::iterator viter = versions.begin(); viter != versions.end(); viter++) {
198 std::string version = *viter;
199 Json2::Value commands = versionMembers[version];
200 if (!commands.IsObject()) {
201 continue;
202 }
203 Json2::Value::Members members = commands.GetMemberNames();
204
205 ApplyConfigMembers(commands, members);
206 }
207 }
208 }
209
ApplyConfigMembers(const Json2::Value & commands,const Json2::Value::Members & members) const210 void CommandLineInterface::ApplyConfigMembers(const Json2::Value& commands,
211 const Json2::Value::Members& members) const
212 {
213 for (Json2::Value::Members::const_iterator iter = members.begin(); iter != members.end(); iter++) {
214 std::string key = *iter;
215 if (!commands[key].IsObject() || !commands[key].IsMember("args") || !commands[key]["args"].IsObject()) {
216 ELOG("Invalid JSON: %s", commands[key].AsString().c_str());
217 continue;
218 }
219 Json2::Value val = commands[key]["args"];
220 std::unique_ptr<CommandLine> command =
221 CommandLineFactory::CreateCommandLine(key, CommandLine::CommandType::SET, val, *socket);
222 ApplyConfigCommands(key, command);
223 }
224 }
225
ApplyConfigCommands(const std::string & key,const std::unique_ptr<CommandLine> & command) const226 void CommandLineInterface::ApplyConfigCommands(const std::string& key,
227 const std::unique_ptr<CommandLine>& command) const
228 {
229 if (command == nullptr) {
230 ELOG("Unsupported configuration: %s", key.c_str());
231 return;
232 }
233
234 if (command->IsArgValid()) {
235 command->RunSet();
236 }
237 }
238
Init(std::string pipeBaseName)239 void CommandLineInterface::Init(std::string pipeBaseName)
240 {
241 CommandLineFactory::InitCommandMap();
242 InitPipe(pipeBaseName);
243 }
244
ReadAndApplyConfig(std::string path) const245 void CommandLineInterface::ReadAndApplyConfig(std::string path) const
246 {
247 if (path.empty()) {
248 return;
249 }
250 std::string jsonStr = JsonReader::ReadFile(path);
251 Json2::Value val = JsonReader::ParseJsonData2(jsonStr);
252 ApplyConfig(val);
253 }
254
CreatCommandToSendData(const std::string commandName,const Json2::Value & jsonData,const std::string type) const255 void CommandLineInterface::CreatCommandToSendData(const std::string commandName,
256 const Json2::Value& jsonData,
257 const std::string type) const
258 {
259 CommandLine::CommandType commandType = GetCommandType(type);
260 std::unique_ptr<CommandLine> commandLine =
261 CommandLineFactory::CreateCommandLine(commandName, commandType, jsonData, *socket);
262 if (commandLine == nullptr) {
263 ELOG("Unsupported CreatCommandToSendData: %s", commandName.c_str());
264 return;
265 }
266 commandLine->RunAndSendResultToManager();
267 }
268
IsStaticIgnoreCmd(const std::string cmd) const269 bool CommandLineInterface::IsStaticIgnoreCmd(const std::string cmd) const
270 {
271 auto it = std::find(staticIgnoreCmd.begin(), staticIgnoreCmd.end(), cmd);
272 if (it != staticIgnoreCmd.end()) {
273 return false;
274 } else {
275 return true;
276 }
277 }
278