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