text: from gevent import monkey;monkey.patch_all()
  import gevent
  from gevent import socket
  from enum import Enum
  
  from bee.errors.error import CodedError
  
  from bee.data.guid.guid import Guid
  from bee.data.map import Map
  from bee.net.rpc.channel import Channel
  from bee.net.rpc.codec import CodecBuilder, RequestHead, Request, ResponseHead, Result
  
  from gsocketpool import Pool
  from gsocketpool import TcpConnection
  """default max connectinos"""
  default_max_connections = 100
  """default max error count"""
  default_max_error_count = 10
  
  class NodeState(Enum):
      """
      fail mode
      """
      """Idle indicates the Node is idle"""
      Idle = 0
      """Ready indicates the Node is ready for work"""
      Ready = 1
      """Shutdown indicates the Node has started shutting down"""
      Shutdown = 2
  
  
  class Node():
  
      def __init__(self, id: str, address: str, status: NodeState = NodeState.Ready, cb: CodecBuilder = None,
                   connect_timeout=5):
          self.id = id
          self.address = address
          self.status = status
          self._cb = cb
          pair = address.split(":")
          options = dict(host=pair[0], port=int(pair[1]), timeout=connect_timeout)
          self.pool: Pool = Pool(TcpConnection, options,
                                 # initial_connections=1,
                                 max_connections=default_max_connections,
                                 reap_expired_connections=False)
          self.error_count = 0
  
          self.count = 1
  
          # self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          # self.sock.connect((pair[0], int(pair[1])))
  
      def __str__(self):
          return "Node(id={}, address={}, status={}(value={}))".format(self.id, self.address, self.status,
                                                                       self.status.value)
      def call(self, service: str, method: str, args=[]) -> Result:
  
          """
          class remote method
          :param service:
          :param method:
          :param args:
          :return:
          """
          print("Node.call(service={}, method={}, args={})".format(service, method, str(args)))
          try:
              with self.pool.connection() as client:
                  if not client.is_connected():
                      client.open()
                  sock = client.socket
                  rh = RequestHead()
                  rh.id = self.count
                  self.count += 1
                  rh.service = service
                  rh.method = method
                  rh.labels = []
                  r = Request(head=rh, args=args)
                  cc = self._cb.new_client_codec(s=Channel(id=Guid().string(), sock=sock), opts=Map())
                  cc.encode(req=r)
                  rh = ResponseHead()
                  cc.decode_head(rh)
                  rt = Result()
                  cc.decode_result(rt)
                  return rt
  
          except Exception as e:
              self.error_count +=1
              if (self.error_count >= default_max_error_count):
                  self.report_error()
              raise CodedError(code=-1, message=e.__str__(), detail=e.__str__())
  
      def report_error(self):
          self.status = NodeState.Shutdown
          gevent.spawn(self.hearbeat())
  
  
      def hearbeat(self):
          #TODO; heartbeat retry
          pass