1 #ifdef BT_ENABLE_GRPC
2 #include "PhysicsClientGRPC.h"
3 #include "SharedMemory/grpc/proto/pybullet.grpc.pb.h"
4 #include <grpc++/grpc++.h>
5 using grpc::Channel;
6 #include <stdio.h>
7 #include <string.h>
8 #include "../Utils/b3Clock.h"
9 #include "PhysicsClient.h"
10 //#include "LinearMath/btVector3.h"
11 #include "SharedMemoryCommands.h"
12 #include <string>
13 #include "Bullet3Common/b3Logging.h"
14 #include "Bullet3Common/b3AlignedObjectArray.h"
15 #include "SharedMemory/grpc/ConvertGRPCBullet.h"
16 
17 using pybullet_grpc::grpc::PyBulletAPI;
18 
b3DeserializeInt2(const unsigned char * input)19 static unsigned int b3DeserializeInt2(const unsigned char* input)
20 {
21 	unsigned int tmp = (input[3] << 24) + (input[2] << 16) + (input[1] << 8) + input[0];
22 	return tmp;
23 }
24 
25 bool gVerboseNetworkMessagesClient3 = false;
26 
27 struct GRPCNetworkedInternalData
28 {
29 	std::shared_ptr<grpc::Channel> m_grpcChannel;
30 	std::unique_ptr<PyBulletAPI::Stub> m_stub;
31 
32 	bool m_isConnected;
33 
34 	SharedMemoryCommand m_clientCmd;
35 	bool m_hasCommand;
36 
37 	SharedMemoryStatus m_lastStatus;
38 	b3AlignedObjectArray<char> m_stream;
39 
40 	std::string m_hostName;
41 	int m_port;
42 
43 	b3AlignedObjectArray<unsigned char> m_tempBuffer;
44 	double m_timeOutInSeconds;
45 
GRPCNetworkedInternalDataGRPCNetworkedInternalData46 	GRPCNetworkedInternalData()
47 		: m_isConnected(false),
48 		  m_hasCommand(false),
49 		  m_timeOutInSeconds(60)
50 	{
51 	}
52 
disconnectGRPCNetworkedInternalData53 	void disconnect()
54 	{
55 		if (m_isConnected)
56 		{
57 			m_stub = 0;
58 			m_grpcChannel = 0;
59 			m_isConnected = false;
60 		}
61 	}
connectGRPCGRPCNetworkedInternalData62 	bool connectGRPC()
63 	{
64 		if (m_isConnected)
65 			return true;
66 		std::string hostport = m_hostName;
67 		if (m_port >= 0)
68 		{
69 			hostport += ':' + std::to_string(m_port);
70 		}
71 		m_grpcChannel = grpc::CreateChannel(
72 			hostport, grpc::InsecureChannelCredentials());
73 
74 		m_stub = PyBulletAPI::NewStub(m_grpcChannel);
75 
76 		// Set timeout for API
77 		std::chrono::system_clock::time_point deadline =
78 			std::chrono::system_clock::now() + std::chrono::seconds((long long)m_timeOutInSeconds);
79 		grpc::ClientContext context;
80 		context.set_deadline(deadline);
81 		::pybullet_grpc::PyBulletCommand request;
82 		pybullet_grpc::CheckVersionCommand* cmd1 = request.mutable_checkversioncommand();
83 		cmd1->set_clientversion(SHARED_MEMORY_MAGIC_NUMBER);
84 		::pybullet_grpc::PyBulletStatus response;
85 		// The actual RPC.
86 		grpc::Status status = m_stub->SubmitCommand(&context, request, &response);
87 		if (response.has_checkversionstatus())
88 		{
89 			if (response.checkversionstatus().serverversion() == SHARED_MEMORY_MAGIC_NUMBER)
90 			{
91 				m_isConnected = true;
92 			}
93 			else
94 			{
95 				printf("Error: Client version (%d) is different from server version (%d)", SHARED_MEMORY_MAGIC_NUMBER, response.checkversionstatus().serverversion());
96 			}
97 		}
98 		else
99 		{
100 			printf("Error: cannot connect to GRPC server\n");
101 		}
102 
103 		return m_isConnected;
104 	}
105 
checkDataGRPCNetworkedInternalData106 	bool checkData()
107 	{
108 		bool hasStatus = false;
109 		return hasStatus;
110 	}
111 };
112 
GRPCNetworkedPhysicsProcessor(const char * hostName,int port)113 GRPCNetworkedPhysicsProcessor::GRPCNetworkedPhysicsProcessor(const char* hostName, int port)
114 {
115 	m_data = new GRPCNetworkedInternalData;
116 	if (hostName)
117 	{
118 		m_data->m_hostName = hostName;
119 	}
120 	m_data->m_port = port;
121 }
122 
~GRPCNetworkedPhysicsProcessor()123 GRPCNetworkedPhysicsProcessor::~GRPCNetworkedPhysicsProcessor()
124 {
125 	disconnect();
126 	delete m_data;
127 }
128 
processCommand(const struct SharedMemoryCommand & clientCmd,struct SharedMemoryStatus & serverStatusOut,char * bufferServerToClient,int bufferSizeInBytes)129 bool GRPCNetworkedPhysicsProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
130 {
131 	if (gVerboseNetworkMessagesClient3)
132 	{
133 		printf("GRPCNetworkedPhysicsProcessor::processCommand\n");
134 	}
135 
136 	::pybullet_grpc::PyBulletCommand grpcCommand;
137 	pybullet_grpc::PyBulletCommand* grpcCmdPtr = convertBulletToGRPCCommand(clientCmd, grpcCommand);
138 
139 	if (grpcCmdPtr)
140 	{
141 		grpc::ClientContext context;
142 		std::chrono::system_clock::time_point deadline =
143 			std::chrono::system_clock::now() + std::chrono::seconds((long long)m_data->m_timeOutInSeconds);
144 		context.set_deadline(deadline);
145 		::pybullet_grpc::PyBulletStatus status;
146 		// The actual RPC.
147 		grpc::Status grpcStatus = m_data->m_stub->SubmitCommand(&context, grpcCommand, &status);
148 
149 		//convert grpc status to Bullet status
150 		bool convertedOk = convertGRPCToStatus(status, serverStatusOut, bufferServerToClient, bufferSizeInBytes);
151 		if (!convertedOk)
152 		{
153 			disconnect();
154 		}
155 		return convertedOk;
156 	}
157 
158 	return false;
159 }
160 
receiveStatus(struct SharedMemoryStatus & serverStatusOut,char * bufferServerToClient,int bufferSizeInBytes)161 bool GRPCNetworkedPhysicsProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
162 {
163 	bool hasStatus = m_data->checkData();
164 
165 	if (hasStatus)
166 	{
167 		if (gVerboseNetworkMessagesClient3)
168 		{
169 			printf("GRPCNetworkedPhysicsProcessor::receiveStatus\n");
170 		}
171 
172 		serverStatusOut = m_data->m_lastStatus;
173 		int numStreamBytes = m_data->m_stream.size();
174 
175 		if (numStreamBytes < bufferSizeInBytes)
176 		{
177 			for (int i = 0; i < numStreamBytes; i++)
178 			{
179 				bufferServerToClient[i] = m_data->m_stream[i];
180 			}
181 		}
182 		else
183 		{
184 			printf("Error: steam buffer overflow\n");
185 		}
186 	}
187 
188 	return hasStatus;
189 }
190 
renderScene(int renderFlags)191 void GRPCNetworkedPhysicsProcessor::renderScene(int renderFlags)
192 {
193 }
194 
physicsDebugDraw(int debugDrawFlags)195 void GRPCNetworkedPhysicsProcessor::physicsDebugDraw(int debugDrawFlags)
196 {
197 }
198 
setGuiHelper(struct GUIHelperInterface * guiHelper)199 void GRPCNetworkedPhysicsProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper)
200 {
201 }
202 
isConnected() const203 bool GRPCNetworkedPhysicsProcessor::isConnected() const
204 {
205 	return m_data->m_isConnected;
206 }
207 
connect()208 bool GRPCNetworkedPhysicsProcessor::connect()
209 {
210 	bool isConnected = m_data->connectGRPC();
211 	return isConnected;
212 }
213 
disconnect()214 void GRPCNetworkedPhysicsProcessor::disconnect()
215 {
216 	m_data->disconnect();
217 }
218 
setTimeOut(double timeOutInSeconds)219 void GRPCNetworkedPhysicsProcessor::setTimeOut(double timeOutInSeconds)
220 {
221 	m_data->m_timeOutInSeconds = timeOutInSeconds;
222 }
223 
224 #endif  //BT_ENABLE_GRPC
225