12 namespace droid.Runtime.Messaging {
25 #region PrivateMembers 29 Thread _polling_thread;
31 int _last_send_frame_number;
33 float _last_send_time;
38 Thread _wait_for_client_thread;
42 object _stop_lock =
new object();
44 object _thread_lock =
new object();
52 bool _waiting_for_main_loop_to_send;
56 bool _use_inter_process_communication;
64 ResponseSocket _socket;
81 Double _wait_time_seconds;
83 const string _api_version =
"0.1.2";
87 #region PrivateMethods 95 void BindSocket(Action callback, Action<String> debug_callback) {
96 if (this._debugging) {
97 debug_callback?.Invoke(
"Start listening for clients");
101 if (this._use_inter_process_communication) {
102 this._socket.Bind(
"ipc:///tmp/neodroid/messages");
104 this._socket.Bind(
"tcp://" + this._ip_address +
":" + this._port);
108 if (this._debugging) {
109 debug_callback?.Invoke(
"Now listening for clients");
112 this._Listening_For_Clients =
true;
113 }
catch (Exception exception) {
114 if (this._debugging) {
115 debug_callback?.Invoke($
"BindSocket threw exception: {exception}");
128 lock (this._thread_lock) {
132 if (wait_time > TimeSpan.Zero) {
134 var received = this._socket.TryReceiveFrameBytes(wait_time, out msg);
135 if (this.Debugging) {
137 Debug.Log(
"Received frame bytes");
139 Debug.Log($
"Received nothing in {wait_time} seconds");
143 this._socket.TryReceiveFrameBytes(wait_time, out msg);
147 msg = this._socket.ReceiveFrameBytes();
148 }
catch (ArgumentNullException e) {
156 var tuple = FbsReactionUtilities.deserialise_reactions(flat_reaction);
157 reactions = tuple.Item1;
158 var close = tuple.Item2;
159 var api_version = tuple.Item3;
160 var simulator_configuration = tuple.Item4;
162 }
catch (Exception exception) {
163 if (exception is TerminatingException) {
167 Debug.Log(exception);
179 void PollingThread(Action<
Reaction[]> receive_callback,
180 Action disconnect_callback,
181 Action<string> debug_callback) {
182 while (this._stop_thread ==
false) {
183 lock (this._thread_lock) {
184 if (!this._waiting_for_main_loop_to_send) {
185 var reactions = this.Receive(TimeSpan.FromSeconds(
this._wait_time_seconds));
186 if (reactions != null) {
187 receive_callback(reactions);
188 this._waiting_for_main_loop_to_send =
true;
191 if (this._debugging) {
192 debug_callback(
"Waiting for main loop to send reply");
198 disconnect_callback();
199 if (!this._socket.IsDisposed) {
200 if (this._use_inter_process_communication) {
201 this._socket.Disconnect(
"inproc://neodroid");
203 this._socket.Disconnect(
"tcp://" + this._ip_address +
":" + this._port);
208 this._socket.Dispose();
209 this._socket.Close();
211 NetMQConfig.Cleanup(
false);
219 #region PublicMethods 230 bool do_serialise_unobservables =
false,
231 bool serialise_individual_observables =
false,
232 bool serialise_aggregated_float_array =
false,
234 string api_version = _api_version) {
235 lock (this._thread_lock) {
237 if (this.Debugging) {
238 var environment_state = environment_states.ToArray();
239 if (environment_state.Length > 0) {
240 if (environment_state[0] != null) {
241 var frame_number = environment_state[0].
FrameNumber;
242 var time = environment_state[0].Time;
243 var frame_number_duplicate = this._last_send_frame_number == frame_number;
244 if (frame_number_duplicate && frame_number > 0) {
245 Debug.LogWarning($
"Sending duplicate frame! Frame number: {frame_number}");
248 if (frame_number <= this._last_send_frame_number) {
249 Debug.LogWarning($
"The current frame number {frame_number} is less or equal the last {this._last_send_frame_number}, SINCE AWAKE ({Time.frameCount})");
252 if (time <= this._last_send_time) {
253 Debug.LogWarning($
"The current time {time} is less or equal the last {this._last_send_time}");
256 if (environment_state[0].Description != null) {
257 Debug.Log($
"State has description: {environment_state[0].Description}");
260 this._last_send_frame_number = frame_number;
261 this._last_send_time = time;
264 Debug.LogWarning(
"No environment states where send.");
269 this._byte_buffer = FbsStateUtilities.Serialise(environment_states,
270 do_serialise_unobservables :
271 do_serialise_unobservables,
272 serialise_individual_observables :
273 serialise_individual_observables,
274 simulator_configuration :
275 simulator_configuration_message,
276 do_serialise_aggregated_float_array :
277 serialise_aggregated_float_array,
278 api_version : api_version);
279 this._socket.SendFrame(this._byte_buffer);
280 this._waiting_for_main_loop_to_send =
false;
288 this.BindSocket(null, debug_callback);
296 this._wait_for_client_thread =
297 new Thread(unused_param => this.BindSocket(callback, debug_callback)) {IsBackground =
true};
299 this._wait_for_client_thread.Start();
308 Action disconnect_callback,
309 Action<string> debug_callback) {
310 this._polling_thread =
311 new Thread(unused_param => this.PollingThread(cmd_callback, disconnect_callback, debug_callback)) {
316 this._polling_thread.Start();
319 #region Contstruction 323 bool use_inter_process_communication =
false,
325 Double wait_time_seconds = 2) {
326 this._wait_time_seconds = wait_time_seconds;
327 this.Debugging = debug;
328 this._ip_address = ip_address;
330 this._use_inter_process_communication = use_inter_process_communication;
333 if (this.Debugging) {
334 Debug.Log($
"Starting a message server at address:port {ip_address}:{port }");
338 if (!this._use_inter_process_communication) {
342 this._socket =
new ResponseSocket();
345 public MessageServer(
bool debug =
false) : this(
"127.0.0.1", 6969, false, debug) { }
353 public bool Debugging {
get {
return this._debugging; }
set { this._debugging = value; } }
359 #region Deconstruction 369 lock (this._stop_lock) {
370 this._stop_thread =
true;
373 if (this._use_inter_process_communication) {
374 this._socket.Disconnect(
"ipc:///tmp/neodroid/messages");
376 this._socket.Disconnect(
"tcp://" + this._ip_address +
":" + this._port);
380 this._socket.Dispose();
381 this._socket.Close();
383 NetMQConfig.Cleanup(
false);
386 this._wait_for_client_thread?.Join();
387 this._polling_thread?.Join();
389 Console.WriteLine(
"Exception thrown while killing threads");
void SendStates(EnvironmentState[] environment_states, bool do_serialise_unobservables=false, bool serialise_individual_observables=false, bool serialise_aggregated_float_array=false, SimulatorConfigurationMessage simulator_configuration_message=null, string api_version=_api_version)
void ListenForClientToConnect(Action< string > debug_callback)
void StartReceiving(Action< Reaction[]> cmd_callback, Action disconnect_callback, Action< string > debug_callback)
static FReactions GetRootAsFReactions(ByteBuffer _bb)
void ListenForClientToConnect(Action callback, Action< string > debug_callback)
Reaction [] Receive(TimeSpan wait_time)
bool _Listening_For_Clients
MessageServer(string ip_address="127.0.0.1", int port=6969, bool use_inter_process_communication=false, bool debug=false, Double wait_time_seconds=2)
MessageServer(bool debug=false)