Added Devices message to protobuf interface (#141)

* Removed all BAREMETAL ifdefs

* Cleaned up subfolders

* Fixed regression

* Re-added underscores

* Fixed merge conflicts

* Assume RASCSI is always defined

* Fixed mege issue

* Re-added result message

* Added Devices message to protobuf interface

* Fixed typo

* Fixed include file names

* Updated files to be ignored by git

* Merge with develop branch

* Synchronized output with develop branch

* Fixed missing dependency, causing issues when running "make -j1"

* Fixed handling of connection errors

* Improved protobuf interface upwards compatibility

* Use -g instead of -s, this has less conflict potential with future options

* Made log level options consistent (rascsi and rasctl used a different option)
This commit is contained in:
Uwe Seimet 2021-07-22 14:47:08 +02:00 committed by GitHub
parent 3c5a0003a4
commit 62e7727a48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 249 additions and 132 deletions

View File

@ -12,3 +12,8 @@ sasidump
rasdump rasdump
obj obj
bin bin
/rascsi_interface.pb.cpp
/rascsi_interface.pb.h
.project
.cproject
.settings

View File

@ -74,10 +74,10 @@ BINDIR := ./bin/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL) $(BINDIR)/$(SCSIMON) BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL) $(BINDIR)/$(SCSIMON)
SRC_PROTOC = \ SRC_PROTOC = \
rasctl_interface.proto rascsi_interface.proto
SRC_PROTOBUF = \ SRC_PROTOBUF = \
rasctl_interface.pb.cpp rascsi_interface.pb.cpp
SRC_RASCSI = \ SRC_RASCSI = \
rascsi.cpp \ rascsi.cpp \
@ -138,7 +138,7 @@ OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
OBJ_SASIDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SASIDUMP:%.cpp=%.o))) OBJ_SASIDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SASIDUMP:%.cpp=%.o)))
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o))) OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
GEN_PROTOBUF := $(SRC_PROTOBUF) rasctl_interface.pb.h GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
# The following will include all of the auto-generated dependency files (*.d) # The following will include all of the auto-generated dependency files (*.d)
@ -156,7 +156,7 @@ $(OBJDIR)/%.o: %.cpp | $(OBJDIR)
$(SRC_PROTOBUF): $(SRC_PROTOC) $(SRC_PROTOBUF): $(SRC_PROTOC)
echo "-- Generating protobuf-based source files" echo "-- Generating protobuf-based source files"
protoc --cpp_out=. $(SRC_PROTOC) protoc --cpp_out=. $(SRC_PROTOC)
mv rasctl_interface.pb.cc $@ mv rascsi_interface.pb.cc $@
## Build Targets: ## Build Targets:
## all : Rebuild all of the executable files and re-generate ## all : Rebuild all of the executable files and re-generate
@ -169,10 +169,10 @@ ALL: all
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) | $(BINDIR) $(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lz -lpcap -lprotobuf-lite $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lz -lpcap -lprotobuf-lite
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) | $(BINDIR) $(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lprotobuf-lite $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lprotobuf-lite
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR) $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)

View File

@ -28,7 +28,7 @@
#include "exceptions.h" #include "exceptions.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "rasutil.h" #include "rasutil.h"
#include "rasctl_interface.pb.h" #include "rascsi_interface.pb.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/stdout_color_sinks.h"
#include <spdlog/async.h> #include <spdlog/async.h>
@ -38,7 +38,7 @@
using namespace std; using namespace std;
using namespace spdlog; using namespace spdlog;
using namespace rasctl_interface; using namespace rascsi_interface;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
@ -250,75 +250,88 @@ void Reset()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// List Devices // Get the list of attached devices
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
string ListDevice() { Devices GetDevices() {
char type[5]; Devices devices;
char dev_status[_MAX_FNAME+26];
ostringstream s;
bool has_header = false;
type[4] = 0;
for (int i = 0; i < CtrlMax * UnitNum; i++) { for (int i = 0; i < CtrlMax * UnitNum; i++) {
strncpy(dev_status,"",sizeof(dev_status));
// Initialize ID and unit number
int id = i / UnitNum;
int un = i % UnitNum;
Disk *pUnit = disk[i];
// skip if unit does not exist or null disk // skip if unit does not exist or null disk
if (pUnit == NULL || pUnit->IsNULL()) { Disk *pUnit = disk[i];
if (!pUnit || pUnit->IsNULL()) {
continue; continue;
} }
// Output the header Device *device = devices.add_devices();
if (!has_header) {
s << endl // Initialize ID and unit number
<< "+----+----+------+-------------------------------------" << endl device->set_id(i / UnitNum);
<< "| ID | UN | TYPE | DEVICE STATUS" << endl device->set_un(i % UnitNum);
<< "+----+----+------+-------------------------------------" << endl;
LOGINFO( "+----+----+------+-------------------------------------");
LOGINFO( "| ID | UN | TYPE | DEVICE STATUS");
LOGINFO( "+----+----+------+-------------------------------------\n");
has_header = true;
}
// ID,UNIT,Type,Device Status // ID,UNIT,Type,Device Status
char type[5];
type[0] = (char)(pUnit->GetID() >> 24); type[0] = (char)(pUnit->GetID() >> 24);
type[1] = (char)(pUnit->GetID() >> 16); type[1] = (char)(pUnit->GetID() >> 16);
type[2] = (char)(pUnit->GetID() >> 8); type[2] = (char)(pUnit->GetID() >> 8);
type[3] = (char)(pUnit->GetID()); type[3] = (char)(pUnit->GetID());
type[4] = 0;
device->set_type(type);
// mount status output // mount status output
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) { if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
strncpy(dev_status,"X68000 HOST BRIDGE",sizeof(dev_status)); device->set_file("X68000 HOST BRIDGE");
} else if (pUnit->GetID() == MAKEID('S', 'C', 'D', 'P')) { } else if (pUnit->GetID() == MAKEID('S', 'C', 'D', 'P')) {
strncpy(dev_status,"DaynaPort SCSI/Link",sizeof(dev_status)); device->set_file("DaynaPort SCSI/Link");
} else { } else {
Filepath filepath; Filepath filepath;
pUnit->GetPath(filepath); pUnit->GetPath(filepath);
snprintf(dev_status, sizeof(dev_status), "%s", device->set_file(pUnit->IsRemovable() && !pUnit->IsReady() ? "NO MEDIA" : filepath.GetPath());
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
"NO MEDIA" : filepath.GetPath());
} }
// Write protection status // Write protection status
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) { if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
strcat(dev_status, " (WRITEPROTECT)"); device->set_read_only(true);
} }
s << "| " << id << " | " << un << " | " << type << " | " << dev_status << endl;
LOGINFO( "| %d | %d | %s | %s", id, un, type, dev_status);
} }
// If there is no controller, find will be null return devices;
if (!has_header) { }
//---------------------------------------------------------------------------
//
// List and log devices
//
//---------------------------------------------------------------------------
string ListDevices(Devices devices) {
ostringstream s;
if (devices.devices_size()) {
s << endl
<< "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl;
LOGINFO( "+----+----+------+-------------------------------------");
LOGINFO( "| ID | UN | TYPE | DEVICE STATUS");
LOGINFO( "+----+----+------+-------------------------------------\n");
}
else {
return "No images currently attached.\n"; return "No images currently attached.\n";
} }
for (int i = 0; i < devices.devices_size() ; i++) {
Device device = devices.devices(i);
s << "| " << device.id() << " | " << device.un() << " | " << device.type() << " | "
<< device.file() << (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
LOGINFO( "| %d | %d | %s | %s%s", device.id(), device.un(), device.type().c_str(),
device.file().c_str(), device.read_only() ? " (WRITEPROTECT)" : "");
}
s << "+----+----+------+-------------------------------------" << endl; s << "+----+----+------+-------------------------------------" << endl;
LOGINFO( "+----+----+------+-------------------------------------"); LOGINFO( "+----+----+------+-------------------------------------");
return s.str(); return s.str();
@ -574,9 +587,9 @@ bool ProcessCmd(int fd, const Command &command)
pUnit = new SCSIDaynaPort(); pUnit = new SCSIDaynaPort();
break; break;
default: default:
ostringstream msg; ostringstream error;
msg << "rasctl sent a command for an invalid drive type: " << type; error << "rasctl sent a command for an invalid drive type: " << type;
return ReturnStatus(fd, false, msg.str()); return ReturnStatus(fd, false, error.str());
} }
// drive checks files // drive checks files
@ -593,9 +606,9 @@ bool ProcessCmd(int fd, const Command &command)
LOGWARN("rasctl tried to open an invalid file %s", file.c_str()); LOGWARN("rasctl tried to open an invalid file %s", file.c_str());
ostringstream msg; ostringstream error;
msg << "Error : File open error [" << file << "]"; error << "File open error [" << file << "]";
return ReturnStatus(fd, false, msg.str()); return ReturnStatus(fd, false, error.str());
} }
} }
@ -658,9 +671,9 @@ bool ProcessCmd(int fd, const Command &command)
pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) { pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) {
LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, type_str); LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, type_str);
ostringstream msg; ostringstream error;
msg << "Error : Operation denied (Device type " << type_str << " isn't removable)"; error << "Operation denied (Device type " << type_str << " isn't removable)";
return ReturnStatus(fd, false, msg.str()); return ReturnStatus(fd, false, error.str());
} }
switch (cmd) { switch (cmd) {
@ -669,10 +682,10 @@ bool ProcessCmd(int fd, const Command &command)
LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", params.c_str(), type_str, id, un); LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", params.c_str(), type_str, id, un);
if (!pUnit->Open(filepath)) { if (!pUnit->Open(filepath)) {
ostringstream msg; ostringstream error;
msg << "Error : File open error [" << params << "]"; error << "File open error [" << params << "]";
return ReturnStatus(fd, false, msg.str()); return ReturnStatus(fd, false, error.str());
} }
break; break;
@ -692,10 +705,10 @@ bool ProcessCmd(int fd, const Command &command)
break; break;
default: default:
ostringstream msg; ostringstream error;
msg << "Received unknown command from rasctl: " << cmd; error << "Received unknown command from rasctl: " << cmd;
LOGWARN("%s", msg.str().c_str()); LOGWARN("%s", error.str().c_str());
return ReturnStatus(fd, false, msg.str()); return ReturnStatus(fd, false, error.str());
} }
return ReturnStatus(fd, true); return ReturnStatus(fd, true);
@ -718,7 +731,7 @@ bool ParseArgument(int argc, char* argv[])
string log_level = "trace"; string log_level = "trace";
int opt; int opt;
while ((opt = getopt(argc, argv, "-IiHhL:l:D:d:")) != -1) { while ((opt = getopt(argc, argv, "-IiHhG:g:D:d:")) != -1) {
switch (tolower(opt)) { switch (tolower(opt)) {
case 'i': case 'i':
is_sasi = false; is_sasi = false;
@ -732,7 +745,7 @@ bool ParseArgument(int argc, char* argv[])
id = -1; id = -1;
continue; continue;
case 'l': case 'g':
log_level = optarg; log_level = optarg;
continue; continue;
@ -801,7 +814,9 @@ bool ParseArgument(int argc, char* argv[])
SetLogLevel(log_level); SetLogLevel(log_level);
// Display the device list // Display the device list
fprintf(stdout, "%s", ListDevice().c_str()); Devices devices = GetDevices();
cout << ListDevices(devices) << endl;
return true; return true;
} }
@ -868,12 +883,11 @@ static void *MonThread(void *param)
// List all of the devices // List all of the devices
if (command.cmd() == LIST) { if (command.cmd() == LIST) {
Result result; Devices devices = GetDevices();
result.set_msg(ListDevice() + "\n"); ListDevices(devices);
result.set_status(true);
string data; string data;
result.SerializeToString(&data); devices.SerializeToString(&data);
SerializeProtobufData(fd, data); SerializeProtobufData(fd, data);
} }
else if (command.cmd() == LOG_LEVEL) { else if (command.cmd() == LOG_LEVEL) {
@ -912,6 +926,8 @@ static void *MonThread(void *param)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION;
int i; int i;
int actid; int actid;
DWORD now; DWORD now;

View File

@ -0,0 +1,57 @@
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
package rascsi_interface;
// The supported device types
enum DeviceType {
UNDEFINED = 0;
SASI_HD = 1;
SCSI_HD = 2;
MO = 3;
CD = 4;
BR = 5;
NUVOLINK = 6;
DAYNAPORT = 7;
}
// rascsi remote operations
enum Operation {
NONE = 0;
LIST = 1;
ATTACH = 2;
DETACH = 3;
INSERT = 4;
EJECT = 5;
PROTECT = 6;
LOG_LEVEL = 7;
}
// Commands rascsi can execute
message Command {
Operation cmd = 1;
int32 id = 2;
int32 un = 3;
DeviceType type = 4;
string params = 5;
}
// The result of a command
message Result {
bool status = 1;
string msg = 2;
}
// The device meta data
message Device {
int32 id = 1;
int32 un = 2;
string type = 3;
string file = 4;
bool read_only = 5;
}
message Devices {
repeated Device devices = 1;
}

View File

@ -14,17 +14,19 @@
#include "rascsi_version.h" #include "rascsi_version.h"
#include "exceptions.h" #include "exceptions.h"
#include "rasutil.h" #include "rasutil.h"
#include "rasctl_interface.pb.h" #include "rascsi_interface.pb.h"
#include <sstream>
#include <iostream>
using namespace std; using namespace std;
using namespace rasctl_interface; using namespace rascsi_interface;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Send Command // Send Command
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL SendCommand(const char *hostname, const Command& command) int SendCommand(const char *hostname, const Command& command)
{ {
// Create a socket to send the command // Create a socket to send the command
int fd = socket(AF_INET, SOCK_STREAM, 0); int fd = socket(AF_INET, SOCK_STREAM, 0);
@ -43,24 +45,43 @@ BOOL SendCommand(const char *hostname, const Command& command)
// Connect // Connect
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "Error : Can't connect to rascsi process on host '%s'\n", hostname); cerr << "Error: Can't connect to rascsi process on host '" << hostname << "'" << endl;
return false; return -1;
} }
string data; string data;
command.SerializeToString(&data); command.SerializeToString(&data);
// Receive the message
bool status = true;
try { try {
SerializeProtobufData(fd, data); SerializeProtobufData(fd, data);
}
catch(const ioexception& e) {
cerr << "Error : " << e.getmsg() << endl;
close(fd);
return -1;
}
return fd;
}
//---------------------------------------------------------------------------
//
// Receive command result
//
//---------------------------------------------------------------------------
bool ReceiveResult(int fd) {
bool status = true;
try {
Result result; Result result;
result.ParseFromString(DeserializeProtobufData(fd)); result.ParseFromString(DeserializeProtobufData(fd));
status = result.status(); status = result.status();
if (status) {
if (!result.msg().empty()) { cerr << result.msg();
}
else {
cout << result.msg(); cout << result.msg();
} }
} }
@ -68,6 +89,8 @@ BOOL SendCommand(const char *hostname, const Command& command)
cerr << "Error: " << e.getmsg() << endl; cerr << "Error: " << e.getmsg() << endl;
// Fall through // Fall through
status = false;
} }
close(fd); close(fd);
@ -75,6 +98,31 @@ BOOL SendCommand(const char *hostname, const Command& command)
return status; return status;
} }
string ListDevices(const Devices& devices) {
ostringstream s;
if (devices.devices_size()) {
s << endl
<< "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl;
}
else {
return "No images currently attached.\n";
}
for (int i = 0; i < devices.devices_size() ; i++) {
Device device = devices.devices(i);
s << "| " << device.id() << " | " << device.un() << " | " << device.type() << " | "
<< device.file() << (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
}
s << "+----+----+------+-------------------------------------" << endl;
return s.str();
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Main processing // Main processing
@ -88,7 +136,7 @@ int main(int argc, char* argv[])
if (argc < 2) { if (argc < 2) {
cerr << "SCSI Target Emulator RaSCSI Controller" << endl; cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl; cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-s LOG_LEVEL]" << endl; cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-g LOG_LEVEL]" << endl;
cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl; cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl;
cerr << " UNIT := {0|1} default setting is 0." << endl; cerr << " UNIT := {0|1} default setting is 0." << endl;
cerr << " CMD := {attach|detach|insert|eject|protect}" << endl; cerr << " CMD := {attach|detach|insert|eject|protect}" << endl;
@ -112,7 +160,7 @@ int main(int argc, char* argv[])
const char *hostname = "localhost"; const char *hostname = "localhost";
string params; string params;
opterr = 0; opterr = 0;
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:s:l")) != -1) { while ((opt = getopt(argc, argv, "i:u:c:t:f:h:g:l")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
id = optarg[0] - '0'; id = optarg[0] - '0';
@ -190,7 +238,7 @@ int main(int argc, char* argv[])
hostname = optarg; hostname = optarg;
break; break;
case 's': case 'g':
cmd = LOG_LEVEL; cmd = LOG_LEVEL;
params = optarg; params = optarg;
break; break;
@ -202,14 +250,39 @@ int main(int argc, char* argv[])
if (cmd == LOG_LEVEL) { if (cmd == LOG_LEVEL) {
command.set_cmd(LOG_LEVEL); command.set_cmd(LOG_LEVEL);
command.set_params(params); command.set_params(params);
SendCommand(hostname, command); int fd = SendCommand(hostname, command);
if (fd < 0) {
exit(ENOTCONN);
}
ReceiveResult(fd);
exit(0); exit(0);
} }
// List display only // List display only
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) { if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
command.set_cmd(LIST); command.set_cmd(LIST);
SendCommand(hostname, command); int fd = SendCommand(hostname, command);
if (fd < 0) {
exit(ENOTCONN);
}
Devices devices;
try {
devices.ParseFromString(DeserializeProtobufData(fd));
}
catch(const ioexception& e) {
cerr << "Error : " << e.getmsg() << endl;
close(fd);
exit(-1);
}
close (fd);
cout << ListDevices(devices) << endl;
exit(0); exit(0);
} }
@ -261,10 +334,15 @@ int main(int argc, char* argv[])
if (!params.empty()) { if (!params.empty()) {
command.set_params(params); command.set_params(params);
} }
if (!SendCommand(hostname, command)) {
int fd = SendCommand(hostname, command);
if (fd == -1) {
exit(ENOTCONN); exit(ENOTCONN);
} }
bool status = ReceiveResult(fd);
close(fd);
// All done! // All done!
exit(0); exit(status ? 0 : -1);
} }

View File

@ -1,39 +0,0 @@
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
package rasctl_interface;
enum Operation {
LIST = 0;
ATTACH = 1;
DETACH = 2;
INSERT = 3;
EJECT = 4;
PROTECT = 5;
LOG_LEVEL = 6;
}
enum DeviceType {
UNDEFINED = 0;
SASI_HD = 1;
SCSI_HD = 2;
MO = 3;
CD = 4;
BR = 5;
NUVOLINK = 6;
DAYNAPORT = 7;
}
message Command {
Operation cmd = 1;
int32 id = 2;
int32 un = 3;
DeviceType type = 4;
string params = 5;
}
message Result {
bool status = 1;
string msg = 2;
}