class_docstr: NetGear is exclusively designed to transfer video frames synchronously and asynchronously between interconnecting systems over the network in real-time.
  
  NetGear implements a high-level wrapper around PyZmQ python library that contains python bindings for ZeroMQ - a high-performance asynchronous distributed messaging library
  that provides a message queue, but unlike message-oriented middleware, its system can run without a dedicated message broker.
  
  NetGear also supports real-time Frame Compression capabilities for optimizing performance while sending the frames directly over the network, by encoding the frame before sending
  it and decoding it on the client's end automatically in real-time.
  
  !!! info
      NetGear API now internally implements robust *Lazy Pirate pattern* (auto-reconnection) for its synchronous messaging patterns _(i.e. `zmq.PAIR` & `zmq.REQ/zmq.REP`)_
      at both Server and Client ends, where its API instead of doing a blocking receive, will:
  
      * Poll the socket and receive from it only when it's sure a reply has arrived.
      * Attempt to reconnect, if no reply has arrived within a timeout period.
      * Abandon the connection if there is still no reply after several requests.
  
  NetGear as of now seamlessly supports three ZeroMQ messaging patterns:
  
  - `zmq.PAIR` _(ZMQ Pair Pattern)_
  - `zmq.REQ/zmq.REP` _(ZMQ Request/Reply Pattern)_
  - `zmq.PUB/zmq.SUB` _(ZMQ Publish/Subscribe Pattern)_
  
  _whereas the supported protocol are: `tcp` and `ipc`_.
  
  ??? tip "Modes of Operation"
  
      * **Primary Modes**
  
          NetGear API primarily has two modes of operations:
  
          * **Send Mode:** _which employs `send()` function to send video frames over the network in real-time._
  
          * **Receive Mode:** _which employs `recv()` function to receive frames, sent over the network with *Send Mode* in real-time. The mode sends back confirmation when the
          frame is received successfully in few patterns._
  
      * **Exclusive Modes**
  
          In addition to these primary modes, NetGear API offers applications-specific Exclusive Modes:
  
          * **Multi-Servers Mode:** _In this exclusive mode, NetGear API robustly **handles multiple servers at once**, thereby providing seamless access to frames and unidirectional
          data transfer from multiple Servers/Publishers across the network in real-time._
  
          * **Multi-Clients Mode:** _In this exclusive mode, NetGear API robustly **handles multiple clients at once**, thereby providing seamless access to frames and unidirectional
          data transfer to multiple Client/Consumers across the network in real-time._
  
          * **Bidirectional Mode:** _This exclusive mode **provides seamless support for bidirectional data transmission between between Server and Client along with video frames**._
  
          * **Secure Mode:** _In this exclusive mode, NetGear API **provides easy access to powerful, smart & secure ZeroMQ's Security Layers** that enables strong encryption on
          data, and unbreakable authentication between the Server and Client with the help of custom certificates/keys that brings cheap, standardized privacy and authentication
          for distributed systems over the network._
class_docstr_tok: ["NetGear","is","exclusively","designed","to","transfer","video","frames","synchronously","and","asynchronously","between","interconnecting","systems","over","the","network","in","real-time",".","NetGear","implements","a","high-level","wrapper","around","PyZmQ","python","library","that","contains","python","bindings","for","ZeroMQ","-","a","high-performance","asynchronous","distributed","messaging","library","that","provides","a","message","queue",",","but","unlike","message-oriented","middleware",",","its","system","can","run","without","a","dedicated","message","broker",".","NetGear","also","supports","real-time","Frame","Compression","capabilities","for","optimizing","performance","while","sending","the","frames","directly","over","the","network",",","by","encoding","the","frame","before","sending","it","and","decoding","it","on","the","client","'s","end","automatically","in","real-time",".","!","!","!","info","NetGear","API","now","internally","implements","robust","*","Lazy","Pirate","pattern","*","(","auto-reconnection",")","for","its","synchronous","messaging","patterns","_","(","i.e",".","`","zmq.PAIR","`","&","`","zmq.REQ\/zmq.REP","`",")","_","at","both","Server","and","Client","ends",",","where","its","API","instead","of","doing","a","blocking","receive",",","will",":","*","Poll","the","socket","and","receive","from","it","only","when","it","'s","sure","a","reply","has","arrived",".","*","Attempt","to","reconnect",",","if","no","reply","has","arrived","within","a","timeout","period",".","*","Abandon","the","connection","if","there","is","still","no","reply","after","several","requests",".","NetGear","as","of","now","seamlessly","supports","three","ZeroMQ","messaging","patterns",":","-","`","zmq.PAIR","`","_","(","ZMQ","Pair","Pattern",")","_","-","`","zmq.REQ\/zmq.REP","`","_","(","ZMQ","Request\/Reply","Pattern",")","_","-","`","zmq.PUB\/zmq.SUB","`","_","(","ZMQ","Publish\/Subscribe","Pattern",")","_","_whereas","the","supported","protocol","are",":","`","tcp","`","and","`","ipc","`","_",".","?","?","?","tip","``","Modes","of","Operation","''","*","*","*","Primary","Modes","*","*","NetGear","API","primarily","has","two","modes","of","operations",":","*","*","*","Send","Mode",":","*","*","_which","employs","`","send","(",")","`","function","to","send","video","frames","over","the","network","in","real-time._","*","*","*","Receive","Mode",":","*","*","_which","employs","`","recv","(",")","`","function","to","receive","frames",",","sent","over","the","network","with","*","Send","Mode","*","in","real-time",".","The","mode","sends","back","confirmation","when","the","frame","is","received","successfully","in","few","patterns._","*","*","*","Exclusive","Modes","*","*","In","addition","to","these","primary","modes",",","NetGear","API","offers","applications-specific","Exclusive","Modes",":","*","*","*","Multi-Servers","Mode",":","*","*","_In","this","exclusive","mode",",","NetGear","API","robustly","*","*","handles","multiple","servers","at","once","*","*",",","thereby","providing","seamless","access","to","frames","and","unidirectional","data","transfer","from","multiple","Servers\/Publishers","across","the","network","in","real-time._","*","*","*","Multi-Clients","Mode",":","*","*","_In","this","exclusive","mode",",","NetGear","API","robustly","*","*","handles","multiple","clients","at","once","*","*",",","thereby","providing","seamless","access","to","frames","and","unidirectional","data","transfer","to","multiple","Client\/Consumers","across","the","network","in","real-time._","*","*","*","Bidirectional","Mode",":","*","*","_This","exclusive","mode","*","*","provides","seamless","support","for","bidirectional","data","transmission","between","between","Server","and","Client","along","with","video","frames","*","*","._","*","*","*","Secure","Mode",":","*","*","_In","this","exclusive","mode",",","NetGear","API","*","*","provides","easy","access","to","powerful",",","smart","&","secure","ZeroMQ","'s","Security","Layers","*","*","that","enables","strong","encryption","on","data",",","and","unbreakable","authentication","between","the","Server","and","Client","with","the","help","of","custom","certificates\/keys","that","brings","cheap",",","standardized","privacy","and","authentication","for","distributed","systems","over","the","network._"]
docstr: A threaded receiver handler, that keep iterating data from ZMQ socket to a internally monitored deque,
  until the thread is terminated, or socket disconnects.
docstr_tok: ["A","threaded","receiver","handler",",","that","keep","iterating","data","from","ZMQ","socket","to","a","internally","monitored","deque",",","until","the","thread","is","terminated",",","or","socket","disconnects","."]
code: def __recv_handler(self):
      """
      A threaded receiver handler, that keep iterating data from ZMQ socket to a internally monitored deque,
      until the thread is terminated, or socket disconnects.
      """
      # initialize frame variable
      frame = None
  
      # keep looping infinitely until the thread is terminated
      while not self.__terminate:
          # check queue buffer for overflow
          if len(self.__queue) >= 96:
              # stop iterating if overflowing occurs
              time.sleep(0.000001)
              continue
  
          if self.__pattern < 2:
              socks = dict(self.__poll.poll(self.__request_timeout * 3))
              if socks.get(self.__msg_socket) == zmq.POLLIN:
                  msg_json = self.__msg_socket.recv_json(
                      flags=self.__msg_flag | zmq.DONTWAIT
                  )
              else:
                  logger.critical(
                      "No response from Server(s), Reconnecting again..."
                  )
                  self.__msg_socket.close(linger=0)
                  self.__poll.unregister(self.__msg_socket)
                  self.__max_retries -= 1
  
                  if not (self.__max_retries):
                      if self.__multiserver_mode:
                          logger.error(
                              "All Servers seems to be offline, Abandoning!"
                          )
                      else:
                          logger.error(
                              "Server seems to be offline, Abandoning!"
                          )
                      self.__terminate = True
                      continue
  
                  # Create new connection
                  try:
                      self.__msg_socket = self.__msg_context.socket(
                          self.__msg_pattern
                      )
                      if isinstance(self.__connection_address, list):
                          for _connection in self.__connection_address:
                              self.__msg_socket.bind(_connection)
                      else:
                          self.__msg_socket.bind(
                              self.__connection_address
                          )
                  except Exception as e:
                      logger.exception(str(e))
                      self.__terminate = True
                      raise RuntimeError(
                          "API failed to restart the Client-end!"
                      )
                  self.__poll.register(self.__msg_socket, zmq.POLLIN)
  
                  continue
          else:
              try:
                  msg_json = self.__msg_socket.recv_json(
                      flags=self.__msg_flag
                  )
              except zmq.ZMQError as e:
                  if e.errno == zmq.EAGAIN:
                      logger.critical("Connection Timeout. Exiting!")
                      self.__terminate = True
                      self.__queue.append(None)
                      break
  
          # check if terminate_flag` received
          if msg_json["terminate_flag"]:
              # if multiserver_mode is enabled
              if self.__multiserver_mode:
                  # check and remove from which ports signal is received
                  if msg_json["port"] in self.__port_buffer:
                      # if pattern is 1, then send back server the info about termination
                      if self.__pattern == 1:
                          self.__msg_socket.send_string(
                              "Termination signal successfully received at client!"
                          )
                      self.__port_buffer.remove(msg_json["port"])
                      self.__logging and logger.warning(
                          "Termination signal received from Server at port: {}!".format(
                              msg_json["port"]
                          )
                      )
                  # if termination signal received from all servers then exit client.
                  if not self.__port_buffer:
                      logger.critical(
                          "Termination signal received from all Servers!!!"
                      )
                      self.__terminate = True  # termination
              else:
                  # if pattern is 1, then send back server the info about termination
                  if self.__pattern == 1:
                      self.__msg_socket.send_string(
                          "Termination signal successfully received at Client's end!"
                      )
                  # termination
                  self.__terminate = True
                  # notify client
                  self.__logging and logger.critical(
                      "Termination signal received from server!"
                  )
              continue
  
          msg_data = self.__msg_socket.recv(
              flags=self.__msg_flag | zmq.DONTWAIT,
              copy=self.__msg_copy,
              track=self.__msg_track,
          )
  
          # handle data transfer in synchronous modes.
          if self.__pattern < 2:
              if self.__bi_mode or self.__multiclient_mode:
                  # check if we are returning `ndarray` frames
                  if not (self.__return_data is None) and isinstance(
                      self.__return_data, np.ndarray
                  ):
                      # handle return data for compression
                      return_data = np.copy(self.__return_data)
  
                      # check whether exit_flag is False
                      if not (return_data.flags["C_CONTIGUOUS"]):
                          # check whether the incoming frame is contiguous
                          return_data = np.ascontiguousarray(
                              return_data, dtype=return_data.dtype
                          )
  
                      # handle jpeg-compression encoding
                      if self.__jpeg_compression:
                          if (
                              self.__jpeg_compression_colorspace
                              == "GRAY"
                          ):
                              if return_data.ndim == 2:
                                  # patch for https://gitlab.com/jfolz/simplejpeg/-/issues/11
                                  return_data = return_data[
                                      :, :, np.newaxis
                                  ]
                              return_data = simplejpeg.encode_jpeg(
                                  return_data,
                                  quality=self.__jpeg_compression_quality,
                                  colorspace=self.__jpeg_compression_colorspace,
                                  fastdct=self.__jpeg_compression_fastdct,
                              )
                          else:
                              return_data = simplejpeg.encode_jpeg(
                                  return_data,
                                  quality=self.__jpeg_compression_quality,
                                  colorspace=self.__jpeg_compression_colorspace,
                                  colorsubsampling="422",
                                  fastdct=self.__jpeg_compression_fastdct,
                              )
  
                      return_dict = (
                          dict(port=self.__port)
                          if self.__multiclient_mode
                          else dict()
                      )
  
                      return_dict.update(
                          dict(
                              return_type=(
                                  type(self.__return_data).__name__
                              ),
                              compression={
                                  "dct": self.__jpeg_compression_fastdct,
                                  "ups": self.__jpeg_compression_fastupsample,
                                  "colorspace": self.__jpeg_compression_colorspace,
                              }
                              if self.__jpeg_compression
                              else False,
                              array_dtype=str(self.__return_data.dtype)
                              if not (self.__jpeg_compression)
                              else "",
                              array_shape=self.__return_data.shape
                              if not (self.__jpeg_compression)
                              else "",
                              data=None,
                          )
                      )
  
                      # send the json dict
                      self.__msg_socket.send_json(
                          return_dict, self.__msg_flag | zmq.SNDMORE
                      )
                      # send the array with correct flags
                      self.__msg_socket.send(
                          return_data,
                          flags=self.__msg_flag,
                          copy=self.__msg_copy,
                          track=self.__msg_track,
                      )
                  else:
                      return_dict = (
                          dict(port=self.__port)
                          if self.__multiclient_mode
                          else dict()
                      )
                      return_dict.update(
                          dict(
                              return_type=(
                                  type(self.__return_data).__name__
                              ),
                              data=self.__return_data,
                          )
                      )
                      self.__msg_socket.send_json(
                          return_dict, self.__msg_flag
                      )
              else:
                  # send confirmation message to server
                  self.__msg_socket.send_string(
                      "Data received on device: {} !".format(self.__id)
                  )
          else:
              # else raise warning
              if self.__return_data:
                  logger.warning(
                      "`return_data` is disabled for this pattern!"
                  )
  
          # check if encoding was enabled
          if msg_json["compression"]:
              # decode JPEG frame
              frame = simplejpeg.decode_jpeg(
                  msg_data,
                  colorspace=msg_json["compression"]["colorspace"],
                  fastdct=self.__jpeg_compression_fastdct
                  or msg_json["compression"]["dct"],
                  fastupsample=self.__jpeg_compression_fastupsample
                  or msg_json["compression"]["ups"],
              )
              # check if valid frame returned
              if frame is None:
                  self.__terminate = True
                  # otherwise raise error and exit
                  raise RuntimeError(
                      "[NetGear:ERROR] :: Received compressed JPEG frame decoding failed"
                  )
              if (
                  msg_json["compression"]["colorspace"] == "GRAY"
                  and frame.ndim == 3
              ):
                  # patch for https://gitlab.com/jfolz/simplejpeg/-/issues/11
                  frame = np.squeeze(frame, axis=2)
          else:
              # recover and reshape frame from buffer
              frame_buffer = np.frombuffer(
                  msg_data, dtype=msg_json["dtype"]
              )
              frame = frame_buffer.reshape(msg_json["shape"])
  
          # check if multiserver_mode
          if self.__multiserver_mode:
              # save the unique port addresses
              if not msg_json["port"] in self.__port_buffer:
                  self.__port_buffer.append(msg_json["port"])
              # extract if any message from server and display it
              if msg_json["message"]:
                  self.__queue.append(
                      (msg_json["port"], msg_json["message"], frame)
                  )
              else:
                  # append recovered unique port and frame to queue
                  self.__queue.append((msg_json["port"], frame))
          # extract if any message from server if Bidirectional Mode is enabled
          elif self.__bi_mode:
              if msg_json["message"]:
                  # append grouped frame and data to queue
                  self.__queue.append((msg_json["message"], frame))
              else:
                  self.__queue.append((None, frame))
          else:
              # otherwise append recovered frame to queue
              self.__queue.append(frame)
  
file_path: vidgear/vidgear/gears/netgear.py
imports: import os
  import time
  import string
  import secrets
  import numpy
  import logging
  from threading import Thread
  from collections import deque
  from os.path import expanduser
  from .helper import logger_handler, generate_auth_certificates, check_WriteAccess, check_open_port, import_dependency_safe, logcurr_vidgear_ver
label_desc: Use image node_id 2 for calling the NetGear obj's underlying member method code with example usage: obj.__recv_handler() without return types