class SimplestConnectionEstablishmentPlayer(Locust):
    min_wait = 1000
    max_wait = 1000
    task_set = SimplestConnectionEstablishmentTaskSet

    def _init_sio_client(self):
        try:
            self.client = SocketIO(
                self.host,
                self.port,
                resource='sio',
                transports=['websocket'],
                params={
                    'userid': self.player_id,
                    'roomid': self.room_id
                },
                wait_for_connection=False  # Disabling auto-reconnection.
            )
            '''
      The NodeJs server MUST be using `"socket.io": "1.7.2"` or an error complaining

      "
      ... socketIO_client.__init__, in _get_engineIO_session ...
      ... transport.recv_packet() ...
      "
      
      would be thrown here.
      '''
            self.client.on('connect', self.on_connect)
            self.client.on('disconnect', self.on_disconnect)
            self.client.on('message', self.on_message)
        except ConnectionError:
            print(
                "SimplestConnectionEstablishmentPlayer instance for player.id == %s to room_id == %s. The sio-server is down, try again later."
                % (self.player_id, self.room_id))
            raise GreenletExit()
        except KeyboardInterrupt:
            raise GreenletExit()

    def on_connect(self):
        print(
            'SimplestConnectionEstablishmentPlayer instance for player.id == %s to room_id == %s, connected to sio-server.'
            % (self.player_id, self.room_id))

    def on_disconnect(self):
        '''
    A subtlety to be concerned here. 
    '''
        if (True == self.client._should_stop_waiting()):
            # If the execution reaches here by actively calling `self.client.disconnect()`, then one finds "True == self.client._should_stop_waiting() == self.client._wants_to_close".
            print(
                '[ACTIVELY DISCONNECTED] SimplestConnectionEstablishmentPlayer for player.id == %s to room_id == %s.'
                % (self.player_id, self.room_id))
            raise StopLocust()  # This is within the "main locust".
        else:
            # If the execution reaches here passively within `self.client.wait()`, then one finds "False == self.client._should_stop_waiting() == self.client._wants_to_close", and should help terminate the loop in the spawned `self.client.wait()`. See https://github.com/invisibleroads/socketIO-client/blob/master/socketIO_client/__init__.py for details (socketIO_client v0.7.2).
            print(
                '[PASSIVELY DISCONNECTED] SimplestConnectionEstablishmentPlayer for player.id == %s to room_id == %s.'
                % (self.player_id, self.room_id))
            self.client._close()
            gevent.getcurrent().spawning_greenlet().kill()
            '''
      Killing the current `gevent.Greenlet` instance silently. 

      Quoted from http://www.gevent.org/api/gevent.greenlet.html#gevent.GreenletExit for "gevent v1.3.7.dev0".  

      "
      A special exception that kills the greenlet silently.

      When a greenlet raises GreenletExit or a subclass, the traceback is not printed and the greenlet is considered successful. The exception instance is available under value property as if it was returned by the greenlet, not raised.
      "
      '''
            raise GreenletExit(
            )  # This is within the "spawned greenlet from main locust".

    def on_message(self, *args):
        print(
            'SimplestConnectionEstablishmentPlayer instance for player.id == %s to room_id == %s, on_message %s.'
            % (self.player_id, self.room_id, args))

    def __init__(self, *args, **kwargs):
        '''
    Note that `self.setup` will run within the immediately following invocation if "False == Locust._setup_has_run", see https://github.com/locustio/locust/blob/master/locust/core.py for details (Locust v0.9).
    '''
        super(SimplestConnectionEstablishmentPlayer,
              self).__init__(*args, **kwargs)
        fp = baseoper.get_single_random_player()
        self.player_id = fp[0]
        self.room_id = fp[1]

        sio_server = baseoper.get_sio_server_host_port()
        self.host = sio_server[0]
        self.port = int(sio_server[1])
        '''
    The call to `self._init_sio_client()` SHOULDN'T be put into `"self.setup" or "Locust.setup"` which runs only once for "all locusts spawned by the current OS process", due to "Locust._setup_has_run" being a class-static-variable (unless otherwise hacked via `self._setup_has_run` which is unnecessary), see https://github.com/locustio/locust/blob/master/locust/core.py for details (Locust v0.9).

    Same argument holds for "Locust.teardown", "TaskSet.setup" and "TaskSet.teardown".
    '''
        self._init_sio_client()

    def setup(self):
        print(
            "SimplestConnectionEstablishmentPlayer.setup completed. I'm called only once for all locusts (NOT `once per locust`) during the lifetime of the current OS process."
        )

    def teardown(self):
        print(
            "SimplestConnectionEstablishmentPlayer all instances have been torn down. I'm called only once for all locusts (NOT `once per locust`) during the lifetime of the current OS process."
        )