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
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 Json::Value & value)62 void CommandLineInterface::SendJsonData(const Json::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 Json::Value result;
70 result["version"] = COMMAND_VERSION;
71 result["property"] = "memoryUsage";
72 Json::Value memory;
73 memory["totalBytes"] = static_cast<Json::UInt64>(total);
74 memory["allocBytes"] = static_cast<Json::UInt64>(alloc);
75 memory["peakAllocBytes"] = static_cast<Json::UInt64>(peak);
76 result["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 Json::Value result;
87 Json::Value args;
88 result["MessageType"] = "imageWebsocket";
89 args["port"] = VirtualScreen::webSocketPort;
90 result["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 Json::CharReaderBuilder builder;
116 Json::CharReader* reader = builder.newCharReader();
117 if (reader == nullptr) {
118 FLOG("CommandLineInterface: CharReader memory allocation failed.");
119 }
120
121 Json::Value jsonData;
122 std::string errors; /* NOLINT */
123
124 bool parsingSuccessful = reader->parse(message.c_str(), message.c_str() + message.size(), &jsonData, &errors);
125 delete reader;
126 reader = nullptr;
127
128 if (!ProcessCommandValidate(parsingSuccessful, jsonData, errors)) {
129 return;
130 }
131
132 CommandLine::CommandType type = GetCommandType(jsonData["type"].asString());
133 if (type == CommandLine::CommandType::INVALID) {
134 return;
135 }
136
137 string command = jsonData["command"].asString();
138 std::unique_ptr<CommandLine> commandLine =
139 CommandLineFactory::CreateCommandLine(command, type, jsonData["args"], *socket);
140 if (commandLine == nullptr) {
141 ELOG("Unsupported command");
142 return;
143 }
144 commandLine->CheckAndRun();
145 }
146
ProcessCommandValidate(bool parsingSuccessful,const Json::Value & jsonData,const std::string & errors) const147 bool CommandLineInterface::ProcessCommandValidate(bool parsingSuccessful,
148 const Json::Value& jsonData,
149 const std::string& errors) const
150 {
151 if (!parsingSuccessful) {
152 ELOG("Failed to parse the JSON, errors: %s", errors.c_str());
153 return false;
154 }
155
156 if (!jsonData.isObject()) {
157 ELOG("Command is not a object!");
158 return false;
159 }
160
161 if (!jsonData.isMember("type") || !jsonData.isMember("command") || !jsonData.isMember("version")) {
162 ELOG("Command error!");
163 return false;
164 }
165
166 if (!regex_match(jsonData["version"].asString(), regex("(([0-9]|([1-9]([0-9]*))).){2}([0-9]|([1-9]([0-9]*)))"))) {
167 ELOG("Invalid command version!");
168 return false;
169 }
170 return true;
171 }
172
GetCommandType(string name) const173 CommandLine::CommandType CommandLineInterface::GetCommandType(string name) const
174 {
175 CommandLine::CommandType type = CommandLine::CommandType::INVALID;
176 if (name == "set") {
177 type = CommandLine::CommandType::SET;
178 } else if (name == "get") {
179 type = CommandLine::CommandType::GET;
180 } else if (name == "action") {
181 type = CommandLine::CommandType::ACTION;
182 } else {
183 ELOG("Command type invalid!");
184 }
185 return type;
186 }
187
ApplyConfig(const Json::Value & val) const188 void CommandLineInterface::ApplyConfig(const Json::Value& val) const
189 {
190 const string set("setting");
191 if (val.isMember(set)) {
192 Json::Value versionMembers = val[set];
193 if (!versionMembers.isObject()) {
194 return;
195 }
196
197 Json::Value::Members versions = versionMembers.getMemberNames();
198
199 for (Json::Value::Members::iterator viter = versions.begin(); viter != versions.end(); viter++) {
200 string version = *viter;
201 Json::Value commands = versionMembers[version];
202 if (!commands.isObject()) {
203 continue;
204 }
205 Json::Value::Members members = commands.getMemberNames();
206
207 ApplyConfigMembers(commands, members);
208 }
209 }
210 }
211
ApplyConfigMembers(const Json::Value & commands,const Json::Value::Members & members) const212 void CommandLineInterface::ApplyConfigMembers(const Json::Value& commands,
213 const Json::Value::Members& members) const
214 {
215 for (Json::Value::Members::const_iterator iter = members.begin(); iter != members.end(); iter++) {
216 string key = *iter;
217 if (!commands[key].isObject() || !commands[key].isMember("args") || !commands[key]["args"].isObject()) {
218 ELOG("Invalid JSON: %s", commands[key].asString().c_str());
219 continue;
220 }
221 std::unique_ptr<CommandLine> command =
222 CommandLineFactory::CreateCommandLine(key, CommandLine::CommandType::SET, commands[key]["args"], *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 Json::Value val = JsonReader::ParseJsonData(jsonStr);
253 ApplyConfig(val);
254 }
255
CreatCommandToSendData(const string commandName,const Json::Value jsonData,const string type) const256 void CommandLineInterface::CreatCommandToSendData(const string commandName,
257 const Json::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