DynExp
Highly flexible laboratory automation for dynamically changing experiments.
gRPCModule.h
Go to the documentation of this file.
1 // This file is part of DynExp.
2 
8 #pragma once
9 
10 #include "stdafx.h"
11 #include "DynExpCore.h"
12 #include "../HardwareAdapters/HardwareAdaptergRPC.h"
13 #include "../MetaInstruments/gRPCInstrument.h"
14 
15 namespace DynExpModule
16 {
17  template <typename... gRPCServices>
18  class gRPCModule;
19 
24  template <typename... gRPCServices>
26  {
27  public:
29  virtual ~gRPCModuleData() = default;
30 
31  private:
35  void ResetImpl(dispatch_tag<ModuleDataBase>) override final { Init(); }
36 
41 
46  void Init() {}
47  };
48 
53  template <typename... gRPCServices>
55  {
56  public:
62  : ModuleParamsBase(ID, Core), NetworkParams(*this) {}
63 
64  virtual ~gRPCModuleParams() = default;
65 
69  virtual const char* GetParamClassTag() const noexcept override { return "gRPCModuleParams"; }
70 
72 
73  private:
78 
83 
87  virtual const DynExp::NetworkParamsExtension* GetNetworkAddressParamsChild() const noexcept override { return &NetworkParams; }
88  };
89 
94  template <typename... gRPCServices>
96  {
97  public:
98  using ObjectType = gRPCModule<gRPCServices...>;
99  using ParamsType = gRPCModuleParams<gRPCServices...>;
100 
102  virtual ~gRPCModuleConfigurator() = default;
103  };
104 
114  template <typename... gRPCServices>
116  {
121  template <typename gRPCService>
122  using ServicePtrType = std::unique_ptr<typename gRPCService::AsyncService>;
123 
124  public:
125  using ParamsType = gRPCModuleParams<gRPCServices...>;
126  using ConfigType = gRPCModuleConfigurator<gRPCServices...>;
127  using ModuleDataType = gRPCModuleData<gRPCServices...>;
128 
129  constexpr static auto Name() noexcept { return "gRPC Module"; }
130  constexpr static auto Category() noexcept { return "Network Modules (Servers)"; }
131 
136  : ModuleBase(OwnerThreadID, std::move(Params)),
138 
139  virtual ~gRPCModule() = default;
140 
141  virtual std::string GetName() const override { return Name(); }
142  virtual std::string GetCategory() const override { return Category(); }
143 
148  bool TreatModuleExceptionsAsWarnings() const override { return ServerRunning; }
149 
155  std::chrono::milliseconds GetMainLoopDelay() const override final { return std::chrono::milliseconds(1); }
156 
161  grpc::ServerCompletionQueue* GetServerQueue() const noexcept { return ServerQueue.get(); }
162 
169  template <size_t Index>
170  auto& GetService() const noexcept { return *std::get<Index>(ServicePtrs); }
171 
179  template <typename T>
180  auto& GetService() const noexcept { return *std::get<ServicePtrType<T>>(ServicePtrs); }
181 
182  protected:
188  {
193  enum class StateType {
194  Init,
195  Process,
196  Exit
197  };
198 
203 
204  protected:
209  CallDataBase(const gRPCModule* const OwningModule) noexcept
211 
212  public:
213  virtual ~CallDataBase() {}
214 
219  auto GetOwningModule() const noexcept { return OwningModule; }
220 
227  void Proceed(DynExp::ModuleInstance& Instance) { StateMachine.Invoke(*this, Instance); }
228 
229  protected:
234  auto* GetServerContext() noexcept { return &ServerContext; }
235 
236  private:
241 
246  virtual void InitChild(DynExp::ModuleInstance& Instance) = 0;
247 
255  virtual void ProcessChild(DynExp::ModuleInstance& Instance) = 0;
257 
264  {
265  InitChild(Instance);
266 
267  return StateType::Process;
268  }
269 
276  {
277  ProcessChild(Instance);
278 
279  return StateType::Exit;
280  }
281 
289  {
290  delete this;
291 
292  return StateType::Exit;
293  }
294 
299 
304 
309 
310  const gRPCModule* const OwningModule;
312  grpc::ServerContext ServerContext;
313  };
314 
326  template <typename DerivedType, typename gRPCService, typename RequestMessageType, typename ResponseMessageType,
327  typename std::enable_if_t<Util::is_contained_in_v<gRPCService, gRPCServices...>, int> = 0>
329  {
330  public:
337  static void MakeCall(const gRPCModule* const OwningModule, DynExp::ModuleInstance& Instance) { (new DerivedType(OwningModule))->Proceed(Instance); }
338 
339  private:
340  friend DerivedType;
341 
347  using ResponseWriterType = grpc::ServerAsyncResponseWriter<ResponseMessageType>;
348 
353  using RequestFuncType = std::function<void(typename gRPCService::AsyncService*, grpc::ServerContext*,
354  RequestMessageType*, ResponseWriterType*, grpc::CompletionQueue*, grpc::ServerCompletionQueue*, void*)>;
355 
362  TypedCallDataBase(const gRPCModule* const OwningModule, const RequestFuncType RequestFunc) noexcept
363  : CallDataBase(OwningModule), RequestFunc(RequestFunc), ResponseWriter(this->GetServerContext()) {}
364 
365  virtual ~TypedCallDataBase() = default;
366 
370  void InitChild(DynExp::ModuleInstance& Instance) override final
371  {
372  // The address of *this* instance serves as the tag to distinguish multiple remote procedure calls.
373  RequestFunc(&this->GetOwningModule()->template GetService<gRPCService>(), this->GetServerContext(),
374  &RequestMessage, &ResponseWriter, this->GetOwningModule()->GetServerQueue(), this->GetOwningModule()->GetServerQueue(), this);
375  }
376 
380  void ProcessChild(DynExp::ModuleInstance& Instance) override final
381  {
382  MakeCall(this->GetOwningModule(), Instance);
383 
384  ProcessChildImpl(Instance);
385 
386  ResponseWriter.Finish(ResponseMessage, grpc::Status::OK, this);
387  }
388 
393 
398  virtual void ProcessChildImpl(DynExp::ModuleInstance& Instance) = 0;
400 
402  RequestMessageType RequestMessage;
403  ResponseMessageType ResponseMessage;
405  };
406 
407  private:
413  auto MakeServicePtrTuple() { return std::make_tuple(std::make_unique<typename ServicePtrType<gRPCServices>::element_type>()...); }
414 
419  {
420  void* Tag;
421  bool IsOK;
422 
423  auto Result = ServerQueue->AsyncNext(&Tag, &IsOK, std::chrono::system_clock::now() + std::chrono::milliseconds(80));
424 
425  if (Result == grpc::CompletionQueue::NextStatus::GOT_EVENT && Tag && IsOK)
426  static_cast<CallDataBase*>(Tag)->Proceed(Instance);
427 
429  }
430 
434  void ResetImpl(dispatch_tag<ModuleBase>) override final
435  {
436  ServerQueue.reset();
437  Server.reset();
438 
440  ServerRunning = false;
441 
443  }
444 
449 
454 
465 
471  virtual void OnInitChild(DynExp::ModuleInstance* Instance) const {}
472 
478  virtual void OnExitChild(DynExp::ModuleInstance* Instance) const {}
480 
485 
491  void OnInit(DynExp::ModuleInstance* Instance) const override final
492  {
493  std::string Address;
494  std::string ObjName;
495 
496  {
497  auto ModuleParams = DynExp::dynamic_Params_cast<gRPCModule>(Instance->ParamsGetter());
498  Address = ModuleParams->NetworkParams.MakeAddress();
499  ObjName = ModuleParams->ObjectName;
500  } // ModuleParams unlocked here.
501 
502  grpc::ServerBuilder ServerBuilder;
503  ServerBuilder.AddListeningPort(Address, grpc::InsecureServerCredentials());
504  std::apply([&ServerBuilder](auto&... ServicePtr) { (ServerBuilder.RegisterService(ServicePtr.get()), ...); }, ServicePtrs);
505  ServerQueue = ServerBuilder.AddCompletionQueue();
506  Server = ServerBuilder.BuildAndStart();
507 
509  OnInitChild(Instance);
510 
511  ServerRunning = true;
512  Util::EventLog().Log("gRPC server \"" + ObjName + "\" (" + GetCategoryAndName() + ") listening on " + Address + ".");
513  }
514 
519  void OnExit(DynExp::ModuleInstance* Instance) const override final
520  {
521  OnExitChild(Instance);
522  Shutdown();
523 
524  Util::EventLog().Log("gRPC server \"" + GetObjectName() + "\" (" + GetCategoryAndName() + ") shut down.");
525  }
527 
531  void OnErrorChild(DynExp::ModuleInstance& Instance) const override final
532  {
533  Shutdown();
534  }
535 
540  void Shutdown() const
541  {
542  if (Server)
543  Server->Shutdown();
544  if (ServerQueue)
545  ServerQueue->Shutdown();
546 
548  }
549 
554  void DrainServerQueue() const
555  {
556  if (!ServerQueue)
557  return;
558 
559  bool Result = true;
560  while (Result)
561  {
562  void* Tag = nullptr;
563  bool IsOK;
564  Result = ServerQueue->Next(&Tag, &IsOK);
565 
566  if (Result && Tag)
567  delete static_cast<CallDataBase*>(Tag);
568  }
569  }
570 
574  mutable std::unique_ptr<grpc::ServerCompletionQueue> ServerQueue;
575 
579  mutable std::unique_ptr<grpc::Server> Server;
580 
584  std::tuple<ServicePtrType<gRPCServices>...> ServicePtrs;
585 
589  mutable std::atomic<bool> ServerRunning;
590  };
591 }
Defines DynExp's core module as an interface between the UI and DynExp objects.
Configurator class for gRPCModule.
Definition: gRPCModule.h:96
virtual ~gRPCModuleConfigurator()=default
Data class for gRPCModule.
Definition: gRPCModule.h:26
virtual ~gRPCModuleData()=default
void ResetImpl(dispatch_tag< ModuleDataBase >) override final
Refer to DynExp::ModuleDataBase::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of ...
Definition: gRPCModule.h:35
void Init()
Called by ResetImpl(dispatch_tag<DynExp::ModuleDataBase>) overridden by this class to initialize the ...
Definition: gRPCModule.h:46
virtual void ResetImpl(dispatch_tag< gRPCModuleData >)
Refer to DynExp::ModuleDataBase::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of ...
Definition: gRPCModule.h:40
Parameter class for gRPCModule.
Definition: gRPCModule.h:55
void ConfigureParamsImpl(dispatch_tag< ModuleParamsBase >) override final
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
Definition: gRPCModule.h:77
DynExp::NetworkParamsExtension NetworkParams
Network address the gRPC server listens on.
Definition: gRPCModule.h:71
gRPCModuleParams(DynExp::ItemIDType ID, const DynExp::DynExpCore &Core)
Constructs the parameters for a gRPCModule instance.
Definition: gRPCModule.h:61
virtual void ConfigureParamsImpl(dispatch_tag< gRPCModuleParams >)
Called by DynExp::ParamsBase::ConfigureParams() as a starting point for the tag dispatch mechanism to...
Definition: gRPCModule.h:82
virtual ~gRPCModuleParams()=default
virtual const char * GetParamClassTag() const noexcept override
This function is intended to be overridden once in each derived class returning the name of the respe...
Definition: gRPCModule.h:69
virtual const DynExp::NetworkParamsExtension * GetNetworkAddressParamsChild() const noexcept override
Returns the network address parameters of a derived gRPC instrument. Override GetNetworkAddressParams...
Definition: gRPCModule.h:87
Base class for all TypedCallDataBase classes. Instances of this class manage the state of a single re...
Definition: gRPCModule.h:188
virtual void InitChild(DynExp::ModuleInstance &Instance)=0
Tells gRPC that this CallDataBase instance is ready to handle a respective (as determined by TypedCal...
static constexpr auto ProcessState
State machine state for the StateType::Process state.
Definition: gRPCModule.h:303
StateType InitStateFunc(DynExp::ModuleInstance &Instance)
State function for the CallDataBase::InitState state. Calls InitChild().
Definition: gRPCModule.h:263
Util::StateMachine< StateMachineStateType > StateMachine
State machine based on the states listed in StateType to manage this remote procedure call's state.
Definition: gRPCModule.h:311
StateType ExitStateFunc(DynExp::ModuleInstance &Instance)
State function for the CallDataBase::ExitState state. Deletes this instance.
Definition: gRPCModule.h:288
StateType
Type defining the possible states of remote procedure calls as used by CallDataBase::StateMachine.
Definition: gRPCModule.h:193
@ Init
The remote procedure call's waiting state directly after construction.
@ Process
The remote procedure call's state when it was invoked by a client.
@ Exit
The remote procedure call's state after it has been handled by the server.
CallDataBase(const gRPCModule *const OwningModule) noexcept
Constructs a CallDataBase instance.
Definition: gRPCModule.h:209
static constexpr auto InitState
State machine state for the StateType::Init state.
Definition: gRPCModule.h:298
void Proceed(DynExp::ModuleInstance &Instance)
Calls the state function of the current state of CallDataBase::StateMachine by a call to Util::StateM...
Definition: gRPCModule.h:227
virtual void ProcessChild(DynExp::ModuleInstance &Instance)=0
Creates a new TypedCallDataBase instance of the same type to handle a further remote procedure call,...
static constexpr auto ExitState
State machine state for the StateType::Exit state.
Definition: gRPCModule.h:308
grpc::ServerContext ServerContext
Information about the remote procedure call. Refer to gRPC documentation.
Definition: gRPCModule.h:312
const gRPCModule *const OwningModule
gRPC server this remote procedure call belongs to
Definition: gRPCModule.h:310
StateType ProcessStateFunc(DynExp::ModuleInstance &Instance)
State function for the CallDataBase::ProcessState state. Calls ProcessChild().
Definition: gRPCModule.h:275
auto * GetServerContext() noexcept
Getter for the gRPC server context.
Definition: gRPCModule.h:234
auto GetOwningModule() const noexcept
Getter for the gRPC server this remote procedure call belongs to.
Definition: gRPCModule.h:219
Derive from this class to implement a single remote procedure call handled by this gRPC server gRPCMo...
Definition: gRPCModule.h:329
virtual void ProcessChildImpl(DynExp::ModuleInstance &Instance)=0
Override to implement the server's action to handle this remote procedure call. Particularly,...
grpc::ServerAsyncResponseWriter< ResponseMessageType > ResponseWriterType
Alias for the gRPC response writer which sends a message of type ResponseMessageType back to the clie...
Definition: gRPCModule.h:347
const RequestFuncType RequestFunc
Request function to register the remote procedure call derived from TypedCallDataBase with gRPC.
Definition: gRPCModule.h:401
ResponseWriterType ResponseWriter
gRPC response writer to send gRPCModule::ResponseMessage back to the client. Refer to gRPC documentat...
Definition: gRPCModule.h:404
static void MakeCall(const gRPCModule *const OwningModule, DynExp::ModuleInstance &Instance)
Creates a new remote procedure call of this type which awaits requests from the client.
Definition: gRPCModule.h:337
TypedCallDataBase(const gRPCModule *const OwningModule, const RequestFuncType RequestFunc) noexcept
Constructs a TypedCallDataBase instance.
Definition: gRPCModule.h:362
RequestMessageType RequestMessage
Client's message sent along with its invocation of this remote procedure call.
Definition: gRPCModule.h:402
void InitChild(DynExp::ModuleInstance &Instance) override final
Tells gRPC that this CallDataBase instance is ready to handle a respective (as determined by TypedCal...
Definition: gRPCModule.h:370
ResponseMessageType ResponseMessage
Response the server sends back to the client by finishing the remote procedure call.
Definition: gRPCModule.h:403
std::function< void(typename gRPCService::AsyncService *, grpc::ServerContext *, RequestMessageType *, ResponseWriterType *, grpc::CompletionQueue *, grpc::ServerCompletionQueue *, void *)> RequestFuncType
Alias for the remote procedure call function implemented by this class as part of an asynchronous gRP...
Definition: gRPCModule.h:354
void ProcessChild(DynExp::ModuleInstance &Instance) override final
Creates a new TypedCallDataBase instance of the same type to handle a further remote procedure call,...
Definition: gRPCModule.h:380
Module template for building gRPC servers listening on TCP sockets for network instruments to connect...
Definition: gRPCModule.h:116
void OnInit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread starts. Override it to lock instruments this m...
Definition: gRPCModule.h:491
virtual void CreateInitialCallDataObjectsImpl(DynExp::Object::dispatch_tag< gRPCModule >, DynExp::ModuleInstance &Instance) const =0
Override by derived classes to let them call TypedCallDataBase::MakeCall of the TypedCallDataBase typ...
auto MakeServicePtrTuple()
Constructs the gRPC services (gRPCServices) this gRPC server implements and packs them as a tuple.
Definition: gRPCModule.h:413
grpc::ServerCompletionQueue * GetServerQueue() const noexcept
Getter for the gRPC server's request queue.
Definition: gRPCModule.h:161
virtual void OnInitChild(DynExp::ModuleInstance *Instance) const
Allows derived classes to lock instruments they are controlling (e.g. with calls to DynExp::RunnableI...
Definition: gRPCModule.h:471
std::chrono::milliseconds GetMainLoopDelay() const override final
Specifies in which time intervals the module's event queue runs to handle pending events.
Definition: gRPCModule.h:155
void OnErrorChild(DynExp::ModuleInstance &Instance) const override final
This handler gets called just before the module thread terminates due to an exception....
Definition: gRPCModule.h:531
void Shutdown() const
Shuts down the gRPC server Server and its request queue ServerQueue. Then, it calls DrainServerQueue(...
Definition: gRPCModule.h:540
std::unique_ptr< typename gRPCService::AsyncService > ServicePtrType
Alias for a pointer to a gRPC service.
Definition: gRPCModule.h:122
auto & GetService() const noexcept
Returns a reference to a service this gRPC server implements selected by the service index in the gRP...
Definition: gRPCModule.h:170
bool TreatModuleExceptionsAsWarnings() const override
Determines whether this module should be terminated if an exception leaves the module's main loop or ...
Definition: gRPCModule.h:148
Util::DynExpErrorCodes::DynExpErrorCodes ModuleMainLoop(DynExp::ModuleInstance &Instance) override final
Module main loop. The function is executed periodically by the module thread. Also refer to GetMainLo...
Definition: gRPCModule.h:418
virtual void OnExitChild(DynExp::ModuleInstance *Instance) const
Allows derived classes to unlock instruments they are controlling (e.g. with calls to DynExp::Runnabl...
Definition: gRPCModule.h:478
gRPCModule(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType &&Params)
Constructs a ModuleBase instance.
Definition: gRPCModule.h:135
constexpr static auto Name() noexcept
Every derived class has to redefine this function.
Definition: gRPCModule.h:129
constexpr static auto Category() noexcept
Every derived class has to redefine this function.
Definition: gRPCModule.h:130
std::unique_ptr< grpc::Server > Server
Pointer to the actual gRPC server.
Definition: gRPCModule.h:579
std::tuple< ServicePtrType< gRPCServices >... > ServicePtrs
Tuple of pointers to all the services this gRPC server implements.
Definition: gRPCModule.h:584
void ResetImpl(dispatch_tag< ModuleBase >) override final
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
Definition: gRPCModule.h:434
virtual void ResetImpl(DynExp::Object::dispatch_tag< gRPCModule >)
Refer to DynExp::Object::Reset(). Using tag dispatch mechanism to ensure that ResetImpl() of every de...
Definition: gRPCModule.h:448
virtual ~gRPCModule()=default
std::atomic< bool > ServerRunning
Indicates whether Server is running.
Definition: gRPCModule.h:589
virtual std::string GetName() const override
Returns the name of this Object type.
Definition: gRPCModule.h:141
virtual std::string GetCategory() const override
Returns the category of this Object type.
Definition: gRPCModule.h:142
void OnExit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread terminates (not due to an exception,...
Definition: gRPCModule.h:519
std::unique_ptr< grpc::ServerCompletionQueue > ServerQueue
Queue holding the pending requests made to the gRPC server Server.
Definition: gRPCModule.h:574
void DrainServerQueue() const
Empties ServerQueue removing every request and deleting associated CallDataBase instances.
Definition: gRPCModule.h:554
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
Definition: DynExpCore.h:127
Base class for modules. Modules implement programs on their own (e.g. measurement protocols or server...
Definition: Module.h:392
ModuleBase(const std::thread::id OwnerThreadID, ParamsBasePtrType &&Params)
Constructs a ModuleBase instance.
Definition: Module.cpp:189
Configurator class for ModuleBase.
Definition: Module.h:374
Data structure to contain data which is synchronized in between different threads....
Definition: Module.h:171
Refer to ParamsBase::dispatch_tag.
Definition: Module.h:189
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
Definition: Module.h:793
Parameter class for ModuleBase.
Definition: Module.h:337
ModuleParamsBase(ItemIDType ID, const DynExpCore &Core)
Constructs the parameters for a ModuleBase instance.
Definition: Module.h:348
Bundles several parameters to describe a network connection. Use in parameter classes.
std::string GetCategoryAndName() const
Builds a string from an Object's category and name to allow the user to identify an Object's type.
Definition: Object.h:2158
const std::thread::id OwnerThreadID
Thread id of the thread which has constructed (and owns) this Object instance.
Definition: Object.h:2302
const ParamsBasePtrType Params
Pointer to the parameter class instance belonging to this Object instance.
Definition: Object.h:2303
auto GetObjectName(const std::chrono::milliseconds Timeout=GetParamsTimeoutDefault) const
Returns the name of this Object instance.
Definition: Object.h:2128
Refer to ParamsBase::dispatch_tag.
Definition: Object.h:2018
const ItemIDType ID
ID of the Object this parameter class instance belongs to.
Definition: Object.h:1779
const DynExpCore & Core
Reference to DynExp's core.
Definition: Object.h:1780
Tag for function dispatching mechanism within this class used when derived classes are not intended t...
Definition: Object.h:349
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
Definition: Util.cpp:309
State machine state as used by class StateMachine. A state mainly wraps a state function of the membe...
Definition: Util.h:1305
This class models a state machine. It keeps track of the current state and allows to invoke its assoc...
Definition: Util.h:1435
DynExp's module namespace contains the implementation of DynExp modules which extend DynExp's core fu...
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition: Object.h:1807
size_t ItemIDType
ID type of objects/items managed by DynExp.
DynExpErrorCodes
DynExp's error codes
Definition: Exception.h:22
constexpr bool is_contained_in_v
Value type of is_contained_in.
Definition: Util.h:303
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
Definition: Util.cpp:509
Accumulates include statements to provide a precompiled header.