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 29const std::string CommandLineInterface::COMMAND_VERSION = "1.0.1"; 30bool CommandLineInterface::isFirstWsSend = true; 31bool CommandLineInterface::isPipeConnected = false; 32CommandLineInterface::CommandLineInterface() : socket(nullptr) {} 33 34CommandLineInterface::~CommandLineInterface() {} 35 36void 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 54CommandLineInterface& CommandLineInterface::GetInstance() 55{ 56 static CommandLineInterface instance; /* NOLINT */ 57 return instance; 58} 59 60void CommandLineInterface::SendJsonData(const Json2::Value& value) 61{ 62 *(GetInstance().socket) << value.ToStyledString(); 63} 64 65void 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 82void 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 92void 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 111void 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 144bool 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 171CommandLine::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 186void 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 210void 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 226void 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 239void CommandLineInterface::Init(std::string pipeBaseName) 240{ 241 CommandLineFactory::InitCommandMap(); 242 InitPipe(pipeBaseName); 243} 244 245void 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 255void 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 269bool 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