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 "JsonReader.h"
25 #include "ModelManager.h"
26 #include "PreviewerEngineLog.h"
27 #include "VirtualScreen.h"
28 #include "CommandParser.h"
29
30 using namespace std;
31
32 const string CommandLineInterface::COMMAND_VERSION = "1.0.1";
33 bool CommandLineInterface::isFirstWsSend = true;
34 bool CommandLineInterface::isPipeConnected = false;
CommandLineInterface()35 CommandLineInterface::CommandLineInterface() : socket(nullptr) {}
36
~CommandLineInterface()37 CommandLineInterface::~CommandLineInterface() {}
38
InitPipe(const string name)39 void CommandLineInterface::InitPipe(const string name)
40 {
41 if (socket != nullptr) {
42 socket.reset();
43 ELOG("CommandLineInterface::InitPipe socket is not null");
44 }
45
46 socket = std::make_unique<LocalSocket>();
47 if (socket == nullptr) {
48 FLOG("CommandLineInterface::Connect socket memory allocation failed!");
49 }
50
51 if (!socket->ConnectToServer(socket->GetCommandPipeName(name), LocalSocket::READ_WRITE)) {
52 FLOG("CommandLineInterface command pipe connect failed");
53 }
54 isPipeConnected = true;
55 }
56
GetInstance()57 CommandLineInterface& CommandLineInterface::GetInstance()
58 {
59 static CommandLineInterface instance; /* NOLINT */
60 return instance;
61 }
62
SendJsonData(const Json::Value & value)63 void CommandLineInterface::SendJsonData(const Json::Value& value)
64 {
65 *(GetInstance().socket) << value.toStyledString();
66 }
67
SendJSHeapMemory(size_t total,size_t alloc,size_t peak) const68 void CommandLineInterface::SendJSHeapMemory(size_t total, size_t alloc, size_t peak) const
69 {
70 Json::Value result;
71 result["version"] = COMMAND_VERSION;
72 result["property"] = "memoryUsage";
73 Json::Value memory;
74 memory["totalBytes"] = static_cast<Json::UInt64>(total);
75 memory["allocBytes"] = static_cast<Json::UInt64>(alloc);
76 memory["peakAllocBytes"] = static_cast<Json::UInt64>(peak);
77 result["result"] = memory;
78 if (socket == nullptr) {
79 ELOG("CommandLineInterface::SendJSHeapMemory socket is null");
80 return;
81 }
82 *socket << result.toStyledString();
83 }
84
SendWebsocketStartupSignal() const85 void CommandLineInterface::SendWebsocketStartupSignal() const
86 {
87 Json::Value result;
88 Json::Value args;
89 result["MessageType"] = "imageWebsocket";
90 args["port"] = VirtualScreen::webSocketPort;
91 result["args"] = args;
92 *socket << result.toStyledString();
93 }
94
ProcessCommand() const95 void CommandLineInterface::ProcessCommand() const
96 {
97 string message; /* NOLINT */
98 if (socket == nullptr) {
99 ELOG("CommandLineInterface::ProcessCommand socket is null");
100 return;
101 }
102 if (isPipeConnected && VirtualScreen::isWebSocketListening && isFirstWsSend) {
103 isFirstWsSend = false;
104 SendWebsocketStartupSignal();
105 }
106 *socket >> message;
107 if (message.empty()) {
108 return;
109 }
110
111 ProcessCommandMessage(message);
112 }
113
ProcessCommandMessage(std::string message) const114 void CommandLineInterface::ProcessCommandMessage(std::string message) const
115 {
116 Json::CharReaderBuilder builder;
117 Json::CharReader* reader = builder.newCharReader();
118 if (reader == nullptr) {
119 FLOG("CommandLineInterface: CharReader memory allocation failed.");
120 }
121
122 Json::Value jsonData;
123 std::string errors; /* NOLINT */
124
125 bool parsingSuccessful = reader->parse(message.c_str(), message.c_str() + message.size(), &jsonData, &errors);
126 delete reader;
127 reader = nullptr;
128
129 if (!ProcessCommandValidate(parsingSuccessful, jsonData, errors)) {
130 return;
131 }
132
133 CommandLine::CommandType type = GetCommandType(jsonData["type"].asString());
134 if (type == CommandLine::CommandType::INVALID) {
135 return;
136 }
137
138 string command = jsonData["command"].asString();
139 if (CommandParser::GetInstance().IsStaticCard() && IsStaticIgnoreCmd(command)) {
140 return;
141 }
142 std::unique_ptr<CommandLine> commandLine =
143 CommandLineFactory::CreateCommandLine(command, type, jsonData["args"], *socket);
144 if (commandLine == nullptr) {
145 ELOG("Unsupported command");
146 return;
147 }
148 commandLine->CheckAndRun();
149 }
150
ProcessCommandValidate(bool parsingSuccessful,const Json::Value & jsonData,const std::string & errors) const151 bool CommandLineInterface::ProcessCommandValidate(bool parsingSuccessful,
152 const Json::Value& jsonData,
153 const std::string& errors) const
154 {
155 if (!parsingSuccessful) {
156 ELOG("Failed to parse the JSON, errors: %s", errors.c_str());
157 return false;
158 }
159
160 if (!jsonData.isObject()) {
161 ELOG("Command is not a object!");
162 return false;
163 }
164
165 if (!jsonData.isMember("type") || !jsonData.isMember("command") || !jsonData.isMember("version")) {
166 ELOG("Command error!");
167 return false;
168 }
169
170 if (!regex_match(jsonData["version"].asString(), regex("(([0-9]|([1-9]([0-9]*))).){2}([0-9]|([1-9]([0-9]*)))"))) {
171 ELOG("Invalid command version!");
172 return false;
173 }
174 return true;
175 }
176
GetCommandType(string name) const177 CommandLine::CommandType CommandLineInterface::GetCommandType(string name) const
178 {
179 CommandLine::CommandType type = CommandLine::CommandType::INVALID;
180 if (name == "set") {
181 type = CommandLine::CommandType::SET;
182 } else if (name == "get") {
183 type = CommandLine::CommandType::GET;
184 } else if (name == "action") {
185 type = CommandLine::CommandType::ACTION;
186 } else {
187 ELOG("Command type invalid!");
188 }
189 return type;
190 }
191
ApplyConfig(const Json::Value & val) const192 void CommandLineInterface::ApplyConfig(const Json::Value& val) const
193 {
194 const string set("setting");
195 if (val.isMember(set)) {
196 Json::Value versionMembers = val[set];
197 if (!versionMembers.isObject()) {
198 return;
199 }
200
201 Json::Value::Members versions = versionMembers.getMemberNames();
202
203 for (Json::Value::Members::iterator viter = versions.begin(); viter != versions.end(); viter++) {
204 string version = *viter;
205 Json::Value commands = versionMembers[version];
206 if (!commands.isObject()) {
207 continue;
208 }
209 Json::Value::Members members = commands.getMemberNames();
210
211 ApplyConfigMembers(commands, members);
212 }
213 }
214 }
215
ApplyConfigMembers(const Json::Value & commands,const Json::Value::Members & members) const216 void CommandLineInterface::ApplyConfigMembers(const Json::Value& commands,
217 const Json::Value::Members& members) const
218 {
219 for (Json::Value::Members::const_iterator iter = members.begin(); iter != members.end(); iter++) {
220 string key = *iter;
221 if (!commands[key].isObject() || !commands[key].isMember("args") || !commands[key]["args"].isObject()) {
222 ELOG("Invalid JSON: %s", commands[key].asString().c_str());
223 continue;
224 }
225 std::unique_ptr<CommandLine> command =
226 CommandLineFactory::CreateCommandLine(key, CommandLine::CommandType::SET, commands[key]["args"], *socket);
227 ApplyConfigCommands(key, command);
228 }
229 }
230
ApplyConfigCommands(const string & key,const unique_ptr<CommandLine> & command) const231 void CommandLineInterface::ApplyConfigCommands(const string& key,
232 const unique_ptr<CommandLine>& command) const
233 {
234 if (command == nullptr) {
235 ELOG("Unsupported configuration: %s", key.c_str());
236 return;
237 }
238
239 if (command->IsArgValid()) {
240 command->RunSet();
241 }
242 }
243
Init(string pipeBaseName)244 void CommandLineInterface::Init(string pipeBaseName)
245 {
246 CommandLineFactory::InitCommandMap();
247 InitPipe(pipeBaseName);
248 }
249
ReadAndApplyConfig(string path) const250 void CommandLineInterface::ReadAndApplyConfig(string path) const
251 {
252 if (path.empty()) {
253 return;
254 }
255 string jsonStr = JsonReader::ReadFile(path);
256 Json::Value val = JsonReader::ParseJsonData(jsonStr);
257 ApplyConfig(val);
258 }
259
CreatCommandToSendData(const string commandName,const Json::Value jsonData,const string type) const260 void CommandLineInterface::CreatCommandToSendData(const string commandName,
261 const Json::Value jsonData,
262 const string type) const
263 {
264 CommandLine::CommandType commandType = GetCommandType(type);
265 std::unique_ptr<CommandLine> commandLine =
266 CommandLineFactory::CreateCommandLine(commandName, commandType, jsonData, *socket);
267 if (commandLine == nullptr) {
268 ELOG("Unsupported CreatCommandToSendData: %s", commandName.c_str());
269 return;
270 }
271 commandLine->RunAndSendResultToManager();
272 }
273
IsStaticIgnoreCmd(const string cmd) const274 bool CommandLineInterface::IsStaticIgnoreCmd(const string cmd) const
275 {
276 auto it = std::find(staticIgnoreCmd.begin(), staticIgnoreCmd.end(), cmd);
277 if (it != staticIgnoreCmd.end()) {
278 return false;
279 } else {
280 return true;
281 }
282 }
283