Example #1
0
class WebSocektRFC6455(object):

    def __init__(self, url):
        self.ws = WebSocketClient(url)
        self.queue = Queue.Queue()
        def onmessage(m):
            print "received: %s" % m
            self.queue.put(unicode(str(m), 'utf-8'))

        self.ws.received_message = onmessage

    def connect(self):
        self.ws.connect()
        return self

    def send(self, msg):
        self.ws.send(msg)
        return self

    def recv(self, timeout=1.0):
        try:
            return self.queue.get(timeout=timeout)
        except Queue.Empty:
            raise TimeoutException("websocket didn't receive any thing")

    def close(self):
        self.ws.close()
Example #2
0
    def GET(self):

        url = 'ws://{0}:{1}/yapt/ws?clientname={2}'.format(
            c.conf.YAPT.WebUiAddress, str(c.conf.YAPT.WebUiPort),
            c.conf.YAPT.WebUiPlugin)
        wsc = WebSocketClient(url=url)
        wsc.connect()
        fname = './logs/info.log'
        fsize = os.stat(fname).st_size
        iter = 0
        lines = 17

        with open(fname, 'r') as f:

            bufsize = fsize - 1
            data = []

            while True:

                iter += 1
                f.seek(fsize - bufsize * iter)
                data.extend(f.readlines())

                if len(data) >= lines or f.tell() == 0:
                    # print(''.join(data[-lines:]))
                    wsc.send(payload=json.dumps({
                        'action': c.UI_ACTION_INIT_LOG_VIEWER,
                        'data': ''.join(data[-lines:])
                    }))
                    break
        wsc.close()
        pass
Example #3
0
def printlog(percent, num):

    global ws
    global host
    global port

    stats = {
        'percent': str(percent),
        'img_number': str(cs),
        'tot_images': str(slices)
    }
    post_processing = {
        'name': name,
        'pid': str(myPID),
        'started': str(t0),
        'completed': str(completed),
        'completed_time': str(completed_time),
        'stats': stats
    }
    str_log = {'post_processing': post_processing}
    #str_log='{"post_processing":{"name": "'+name+'","pid": "'+str(myPID)+'","started": "'+str(t0)+'","completed": "'+str(completed)+'","completed_time": "'+str(completed_time)+'","stats":{"percent":"'+str(percent)+'","img_number":'+str(cs)+',"tot_images":'+str(slices)+'}}}'
    message = {'type': 'post_processing', 'data': str_log}

    try:
        ws.send(json.dumps(message))
    except Exception, e:
        print str(e)
        ws = WebSocketClient('ws://' + host + ':' + port + '/')
        ws.connect()
Example #4
0
class WebSocektRFC6455(object):
    def __init__(self, url):
        self.ws = WebSocketClient(url)
        self.queue = Queue.Queue()

        def onmessage(m):
            print "received: %s" % m
            self.queue.put(unicode(str(m), 'utf-8'))

        self.ws.received_message = onmessage

    def connect(self):
        self.ws.connect()
        return self

    def send(self, msg):
        self.ws.send(msg)
        return self

    def recv(self, timeout=1.0):
        try:
            return self.queue.get(timeout=timeout)
        except Queue.Empty:
            raise TimeoutException("websocket didn't receive any thing")

    def close(self):
        self.ws.close()
class SocketWrapper:
    def __init__(self, IP):
        sock = socket.gethostbyname(socket.gethostname())

        # self.addr = "ws://{}:81/ws".format(sock)
        print('Connecting...')
        self.addr = IP
        self.socket = WebSocketClient(self.addr)

        self.socket.connect()
        print('Socket connected:', IP)

    def send_motion(self, ID, arg1, arg2):
        if ID == "~":
            ID = 126
        elif ID == "#":
            ID = 35

        if arg1 == "F":
            arg1 = 70

        payload = [ID, arg1, arg2]
        payload = bytearray(payload)

        self.socket.send(bytearray(payload), True)

    def close(self):
        self.close()
Example #6
0
def main():
    from ws4py.client.threadedclient import WebSocketClient
    from fabtotum.fabui.notify       import NotifyService
    from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient
    from fabtotum.fabui.config import ConfigService
    from fabtotum.os.paths     import RUN_PATH
    import logging
    import argparse
    import os
    
    
    # Setup arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("-L", "--log", help="Use logfile to store log messages.",   default='/var/log/fabui/gpiomonitor.log')
    parser.add_argument("-p", "--pidfile", help="File to store process pid.",       default=os.path.join(RUN_PATH, 'gpiomonitor.pid') )

    # Get arguments
    args = parser.parse_args()
    pidfile = args.pidfile
    
    with open(pidfile, 'w') as f:
        f.write( str(os.getpid()) )
    
    config = ConfigService()

    # Load configuration
    NOTIFY_FILE         = config.get('general', 'notify_file')
    ##################################################################
    SOCKET_HOST         = config.get('socket', 'host')
    SOCKET_PORT         = config.get('socket', 'port')
    ##################################################################
    EVENT_PIN           = config.get('totumduino', 'event_pin')
    
    # Pyro GCodeService wrapper
    gcs = GCodeServiceClient()
    
    ws = WebSocketClient('ws://'+SOCKET_HOST +':'+SOCKET_PORT+'/')
    ws.connect();

    # Notification service
    ns = NotifyService(ws, NOTIFY_FILE, config)
    
    # Setup logger
    logger2 = logging.getLogger('GPIOMonitor')
    logger2.setLevel(logging.DEBUG)
    fh = logging.FileHandler(args.log, mode='w')

    #~ formatter = logging.Formatter("%(name)s - %(levelname)s : %(message)s")
    formatter = logging.Formatter("[%(asctime)s] %(levelname)s : %(message)s")
    fh.setFormatter(formatter)
    fh.setLevel(logging.DEBUG)
    logger2.addHandler(fh)
    
    gpioMonitor = GPIOMonitor(ns, gcs, logger2, EVENT_PIN)
    gpioMonitor.start()
    gpioMonitor.loop()
Example #7
0
class Highlighter:
    def __init__(self):
        self._client = None

    def start(self):
        from ws4py.client.threadedclient import WebSocketClient

        self._client = WebSocketClient('ws://localhost:9090/highlightPub')
        self._client.connect()

    def send(self, block):
        self._client.send(block)
Example #8
0
class AtlIdeThread(myThread):
	def __init__(self, threadID, name, counter, code):
		myThread.__init__(self, threadID, name, counter)
		self._robot = None
		self._origin = None
		self._dataPubThread = None
		self._camClient = None
		self._wsClient = None
		self._consoleClient = None
		self._blocksClient = None
#		self._aruco = aruco

	def start(self):
        # Web Sockets
		# self._camClient = WebSocketClient('ws://localhost:8080/camPub')
		# self._camClient.connect()

		self._wsClient = WebSocketClient('ws://localhost:8080/WsPub')
		self._wsClient.connect()

		# self._consoleClient = WebSocketClient('ws://localhost:8080/consolePub')
		# self._consoleClient.connect()
		#
		# self._cozmo_messagesClient = WebSocketClient('ws://localhost:8080/cozmo_messagesPub')
		# self._cozmo_messagesClient.connect()

		self._blocksClient = WebSocketClient('ws://localhost:8080/blocksPub')
		self._blocksClient.connect()

	def consoleLog(self, msgdata):
		self._consoleClient.send(msgdata)

	def cozmo_messagesLog(self, msgdata):
		self._cozmo_messagesClient.send(msgdata)

	def highlight(self, block, AtlDebugLevel):
		self._blocksClient.send(block)
		print("Highlighting active block " + str(block) + " in " + self.name)
		if AtlDebugLevel == 1:
			time.sleep(1)
		if AtlDebugLevel == 2:
			time.sleep(2)
		if AtlDebugLevel == 3:
			print(block, AtlDebugLevel)
			time.sleep(5)

	def run(self):
		print("Starting " + self.name)
		self.highlight('yq[d`,)DovSfZr-agD8?',0)
		print_time(self.name, 5, self.counter)
		print("Exiting " + self.name)
def skim_test_4_1_2(n_topics=10):
    # test 'globals'
    subLock = threading.Lock()
    subscriptions = dict()
    def received_message(m):
        data = json.loads(m.data)
        if data['op'] == 'publish':
            r_topic = data['topic']
            r_msg = json.dumps(data['msg'])

            with subLock:
                for sub in subscriptions.itervalues():
                    if r_topic == sub['topic']:
                        sub['callback'](r_msg)

    ws = WebSocketClient(ROSBRIDGE_HOST)
    ws.received_message = received_message

    ws.connect()

    current_subID = 1
    for i_top in xrange(n_topics):
        # RUN: One Topic (per topic code)
        topicArrived = threading.Event()
        topicArrived.clear()
        def genf(i_topic=0):
            return lambda data: topicArrived.set()

        # Subscribe
        subID = current_subID
        current_subID += 1
        msg = {'op': 'subscribe', 'topic': SUBTOPIC,
               'type': MSGTYPE, 'id': subID, 'throttle_rate': 5}
        ws.send(json.dumps(msg))
        with subLock:
            subscriptions[subID] = {'callback': genf(i_top),
                                    'topic': SUBTOPIC}

        # Wait for Msg
        got_msg = topicArrived.wait(2.0)

        # Unsubscribe
        msg = {'op': 'unsubscribe', 'id': subID, 'topic': SUBTOPIC}
        with subLock:
            del subscriptions[subID]
        ws.send(json.dumps(msg))
        sleep(0.01)  # 0.1 doesn't seem to cause the problem (after 20hr)...

    ws.close()
Example #10
0
def killAndRaise():
    '''
    global php_script_path
    command = 'sudo php ' + php_script_path +'/kill_raise.php ' + str(monitorPID) + ' "python" "' + python_script_path + '/monitor.py"  &'
    print command
    os.system(command)
    '''
    
    global host
    global port
    global ws
    global SOCKET_CONNECTED
    try:
        ws = WebSocketClient('ws://'+host +':'+port+'/')
        ws.connect();
        SOCKET_CONNECTED = True
    except Exception as inst:
        SOCKET_CONNECTED = False
Example #11
0
def printlog(percent,num):		
	
	global ws
	global host
	global port
	
	stats = {'percent': str(percent), 'img_number': str(cs), 'tot_images': str(slices)}
	post_processing = {'name':  name, 'pid' : str(myPID), 'started': str(t0), 'completed': str(completed), 'completed_time': str(completed_time), 'stats': stats}
	str_log = {'post_processing': post_processing}
	#str_log='{"post_processing":{"name": "'+name+'","pid": "'+str(myPID)+'","started": "'+str(t0)+'","completed": "'+str(completed)+'","completed_time": "'+str(completed_time)+'","stats":{"percent":"'+str(percent)+'","img_number":'+str(cs)+',"tot_images":'+str(slices)+'}}}'
	message = {'type': 'post_processing', 'data': str_log}
	
	try:
		ws.send(json.dumps(message))
	except Exception, e:
		print str(e)
		ws = WebSocketClient('ws://'+host +':'+port+'/')
		ws.connect();
def test_4_1(n_topics=10):
    if 1:
        ws = WebSocketClient(ROSBRIDGE_HOST)
    else:
        ws = RosBridgeClient(ROSBRIDGE_HOST)
    ws.connect()

    topicArrived = threading.Event()
    for i_top in xrange(n_topics):
        topicArrived.clear()
        def genf(i_topic=0):
            return lambda data: topicArrived.set()

        subID = ws.subscribe(SUBTOPIC, MSGTYPE, genf(i_top))
        got_msg = topicArrived.wait(2.0)
        ws.unsubscribe(subID)

    ws.close()
Example #13
0
def killAndRaise():
    '''
    global php_script_path
    command = 'sudo php ' + php_script_path +'/kill_raise.php ' + str(monitorPID) + ' "python" "' + python_script_path + '/monitor.py"  &'
    print command
    os.system(command)
    '''

    global host
    global port
    global ws
    global SOCKET_CONNECTED
    try:
        ws = WebSocketClient('ws://' + host + ':' + port + '/')
        ws.connect()
        SOCKET_CONNECTED = True
    except Exception as inst:
        SOCKET_CONNECTED = False
Example #14
0
def run_gevent():
    from gevent import monkey; monkey.patch_all()
    import gevent
    from ws4py.client.geventclient import WebSocketClient

    ws = WebSocketClient(wss_url)
    ws.connect()
    ws.send("hello")

    def incoming():
        while True:
            m = ws.receive()
            if m is not None:
                print m
            else:
                break
        ws.close()

    gevent.joinall([gevent.spawn(incoming)])
def run_gevent():
    from gevent import monkey; monkey.patch_all()
    import gevent
    from ws4py.client.geventclient import WebSocketClient
    
    ws = WebSocketClient('wss://localhost:9000/ws')
    ws.connect()

    ws.send("hello")
    
    def incoming():
        while True:
            m = ws.receive()
            if m is not None:
                print(m)
            else:
                break
            
        ws.close()

    gevent.joinall([gevent.spawn(incoming)])
Example #16
0
def crd_open_url(host, url):
    """ Opens URL (developer mode only)

        If your Chromecast device is whitelisted, make
        embedded browser navigate to url."""
    try:
        # ask Chrome debugger interface for api endpoint
        resp = requests.get(FORMAT_DEBUG_URL.format(host))
    except requests.exceptions.ConnectionError:
        return False

    payload = json.loads(resp.text)
    wsurl = payload[0]['webSocketDebuggerUrl']

    # format and send api navigate command to the endpoint
    debugcom = FORMAT_CMD.format(url)
    remws = WebSocketClient(wsurl)
    remws.connect()
    remws.send(debugcom)
    remws.close()

    return True
    def test_thread_is_started_once_connected(self, sock):
        s = MagicMock(spec=socket.socket)
        sock.socket.return_value = s
        sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "",
                                          ("127.0.0.1", 80, 0, 0))]
 
        c = WebSocketClient(url="ws://127.0.0.1/")

        def exchange1(*args, **kwargs):
            yield b"\r\n".join([
                    b"HTTP/1.1 101 Switching Protocols",
                    b"Connection: Upgrade",
                    b"Sec-Websocket-Version: 13",
                    b"Content-Type: text/plain;charset=utf-8",
                    b"Sec-Websocket-Accept: " + b64encode(sha1(c.key + WS_KEY).digest()),
                    b"Upgrade: websocket",
                    b"Date: Sun, 26 Jul 2015 12:32:55 GMT",
                    b"Server: ws4py/test",
                    b"\r\n"
                ])

            for i in range(100):
                time.sleep(0.1)
                yield Frame(opcode=OPCODE_TEXT, body=b'hello',
                            fin=1).build()

        s.recv.side_effect = exchange1()
        self.assertFalse(c._th.is_alive())
        
        c.connect()
        time.sleep(0.5)
        self.assertTrue(c._th.is_alive())

        def exchange2(*args, **kwargs):
            yield Frame(opcode=OPCODE_CLOSE, body=b'',
                        fin=1).build()
        s.recv.side_effect = exchange2()
        time.sleep(0.5)
        self.assertFalse(c._th.is_alive())
Example #18
0
class Client(object):
    def __init__(self, listener):
        self.listener = listener
        self._ws_url = 'wss://ws.bitso.com'
        self.ws_client = WebSocketClient(self._ws_url)
        self.ws_client.opened = self.listener.on_connect
        self.ws_client.received_message = self._received
        self.ws_client.closed = self._closed
        self.channels = []

    def connect(self, channels):
        self.channels = channels
        self.ws_client.opened = self._opened
        self.ws_client.connect()
        self.ws_client.run_forever()

    def close(self):
        self.ws_client.close()
        
    def _opened(self):
        for channel in self.channels:
            self.ws_client.send(json.dumps({ 'action': 'subscribe', 'book': 'btc_mxn', 'type': channel }))
        thread.start_new_thread(self._ping_server, ())
        self.listener.on_connect()

    def _received(self, m):
        #print m.data
        val = json.loads(m.data)
        obj = StreamUpdate(val)
        self.listener.on_update(obj)
        
    def _closed(self, code, reason):
        self.listener.on_close(code, reason)
        
    def _ping_server(self):
        while True:
            #keep-alive
            self.ws_client.send(PingControlMessage(u'ping'))
            time.sleep(20)
Example #19
0
    def test_thread_is_started_once_connected(self, sock):
        s = MagicMock(spec=socket.socket)
        sock.socket.return_value = s
        sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM,
                                          0, "", ("127.0.0.1", 80, 0, 0))]

        c = WebSocketClient(url="ws://127.0.0.1/")

        def exchange1(*args, **kwargs):
            yield b"\r\n".join([
                b"HTTP/1.1 101 Switching Protocols", b"Connection: Upgrade",
                b"Sec-Websocket-Version: 13",
                b"Content-Type: text/plain;charset=utf-8",
                b"Sec-Websocket-Accept: " +
                b64encode(sha1(c.key + WS_KEY).digest()),
                b"Upgrade: websocket", b"Date: Sun, 26 Jul 2015 12:32:55 GMT",
                b"Server: ws4py/test", b"\r\n"
            ])

            for i in range(100):
                time.sleep(0.1)
                yield Frame(opcode=OPCODE_TEXT, body=b'hello', fin=1).build()

        s.recv.side_effect = exchange1()
        self.assertFalse(c._th.is_alive())

        c.connect()
        time.sleep(0.5)
        self.assertTrue(c._th.is_alive())

        def exchange2(*args, **kwargs):
            yield Frame(opcode=OPCODE_CLOSE, body=b'', fin=1).build()

        s.recv.side_effect = exchange2()
        time.sleep(0.5)
        self.assertFalse(c._th.is_alive())
Example #20
0
 def connect(self, *args, **kwargs):
     self.pre_connect()
     WebSocketClient.connect(self, *args, **kwargs)
     self.connected = True
def start(port=8080):
	blocksClient = WebSocketClient('ws://localhost:' + str(port)+ '/blocksPub')
	blocksClient.connect()
Example #22
0
 def connect(self):
     WebSocketClient.connect(self)
     self.__thread.start()
Example #23
0
class Client(object):
    """Represents a client connection that connects to Discord.
    This class is used to interact with the Discord WebSocket and API.

    A number of options can be passed to the :class:`Client` via keyword arguments.

    :param int max_length: The maximum number of messages to store in :attr:`messages`. Defaults to 5000.

    Instance attributes:

     .. attribute:: user

         A :class:`User` that represents the connected client. None if not logged in.
     .. attribute:: servers

         A list of :class:`Server` that the connected client has available.
     .. attribute:: private_channels

         A list of :class:`PrivateChannel` that the connected client is participating on.
     .. attribute:: messages

        A deque_ of :class:`Message` that the client has received from all servers and private messages.
     .. attribute:: email

        The email used to login. This is only set if login is successful, otherwise it's None.

    .. _deque: https://docs.python.org/3.4/library/collections.html#collections.deque
    """

    def __init__(self, **kwargs):
        self._is_logged_in = False
        self.user = None
        self.email = None
        self.servers = []
        self.private_channels = []
        self.token = ''
        self.messages = deque([], maxlen=kwargs.get('max_length', 5000))
        self.events = {
            'on_ready': _null_event,
            'on_disconnect': _null_event,
            'on_error': _null_event,
            'on_response': _null_event,
            'on_message': _null_event,
            'on_message_delete': _null_event,
            'on_message_edit': _null_event,
            'on_status': _null_event,
            'on_channel_delete': _null_event,
            'on_channel_create': _null_event,
            'on_channel_update': _null_event,
            'on_member_join': _null_event,
            'on_member_remove': _null_event,
            'on_member_update': _null_event,
            'on_server_create': _null_event,
            'on_server_delete': _null_event,
        }

        # the actual headers for the request...
        # we only override 'authorization' since the rest could use the defaults.
        self.headers = {
            'authorization': self.token,
        }

    def _get_message(self, msg_id):
        return utils.find(lambda m: m.id == msg_id, self.messages)

    def _get_server(self, guild_id):
        return utils.find(lambda g: g.id == guild_id, self.servers)

    def _add_server(self, guild):
        guild['roles'] = [Role(**role) for role in guild['roles']]
        members = guild['members']
        owner = guild['owner_id']
        for i, member in enumerate(members):
            roles = member['roles']
            for j, roleid in enumerate(roles):
                role = utils.find(lambda r: r.id == roleid, guild['roles'])
                if role is not None:
                    roles[j] = role
            members[i] = Member(**member)

            # found the member that owns the server
            if members[i].id == owner:
                owner = members[i]

        for presence in guild['presences']:
            user_id = presence['user']['id']
            member = utils.find(lambda m: m.id == user_id, members)
            if member is not None:
                member.status = presence['status']
                member.game_id = presence['game_id']


        server = Server(owner=owner, **guild)

        # give all the members their proper server
        for member in server.members:
            member.server = server

        channels = [Channel(server=server, **channel) for channel in guild['channels']]
        server.channels = channels
        self.servers.append(server)

    def _create_websocket(self, url, reconnect=False):
        if url is None:
            raise GatewayNotFound()
        log.info('websocket gateway found')
        self.ws = WebSocketClient(url, protocols=['http-only', 'chat'])

        # this is kind of hacky, but it's to avoid deadlocks.
        # i.e. python does not allow me to have the current thread running if it's self
        # it throws a 'cannot join current thread' RuntimeError
        # So instead of doing a basic inheritance scheme, we're overriding the member functions.

        self.ws.opened = self._opened
        self.ws.closed = self._closed
        self.ws.received_message = self._received_message
        self.ws.connect()
        log.info('websocket has connected')

        if reconnect == False:
            second_payload = {
                'op': 2,
                'd': {
                    'token': self.token,
                    'properties': {
                        '$os': sys.platform,
                        '$browser': 'discord.py',
                        '$device': 'discord.py',
                        '$referrer': '',
                        '$referring_domain': ''
                    },
                    'v': 2
                }
            }

            self.ws.send(json.dumps(second_payload))

    def _resolve_mentions(self, content, mentions):
        if isinstance(mentions, list):
            return [user.id for user in mentions]
        elif mentions == True:
            return re.findall(r'<@(\d+)>', content)
        else:
            return []

    def _invoke_event(self, event_name, *args, **kwargs):
        try:
            log.info('attempting to invoke event {}'.format(event_name))
            self.events[event_name](*args, **kwargs)
        except Exception as e:
            log.error('an error ({}) occurred in event {} so on_error is invoked instead'.format(type(e).__name__, event_name))
            self.events['on_error'](event_name, *sys.exc_info())

    def _received_message(self, msg):
        response = json.loads(str(msg))
        log.debug('WebSocket Event: {}'.format(response))
        if response.get('op') != 0:
            return

        self._invoke_event('on_response', response)
        event = response.get('t')
        data = response.get('d')

        if event == 'READY':
            self.user = User(**data['user'])
            guilds = data.get('guilds')

            for guild in guilds:
                self._add_server(guild)

            for pm in data.get('private_channels'):
                self.private_channels.append(PrivateChannel(id=pm['id'], user=User(**pm['recipient'])))

            # set the keep alive interval..
            interval = data.get('heartbeat_interval') / 1000.0
            self.keep_alive = KeepAliveHandler(interval, self.ws)
            self.keep_alive.start()

            # we're all ready
            self._invoke_event('on_ready')
        elif event == 'MESSAGE_CREATE':
            channel = self.get_channel(data.get('channel_id'))
            message = Message(channel=channel, **data)
            self._invoke_event('on_message', message)
            self.messages.append(message)
        elif event == 'MESSAGE_DELETE':
            channel = self.get_channel(data.get('channel_id'))
            message_id = data.get('id')
            found = self._get_message(message_id)
            if found is not None:
                self._invoke_event('on_message_delete', found)
                self.messages.remove(found)
        elif event == 'MESSAGE_UPDATE':
            older_message = self._get_message(data.get('id'))
            if older_message is not None:
                # create a copy of the new message
                message = copy.deepcopy(older_message)
                # update the new update
                for attr in data:
                    if attr == 'channel_id' or attr == 'author':
                        continue
                    value = data[attr]
                    if 'time' in attr:
                        setattr(message, attr, utils.parse_time(value))
                    else:
                        setattr(message, attr, value)
                self._invoke_event('on_message_edit', older_message, message)
                # update the older message
                older_message = message

        elif event == 'PRESENCE_UPDATE':
            server = self._get_server(data.get('guild_id'))
            if server is not None:
                status = data.get('status')
                user = data['user']
                member_id = user['id']
                member = utils.find(lambda m: m.id == member_id, server.members)
                if member is not None:
                    member.status = data.get('status')
                    member.game_id = data.get('game_id')
                    member.name = user.get('username', member.name)
                    member.avatar = user.get('avatar', member.avatar)

                    # call the event now
                    self._invoke_event('on_status', member)
                    self._invoke_event('on_member_update', member)
        elif event == 'USER_UPDATE':
            self.user = User(**data)
        elif event == 'CHANNEL_DELETE':
            server =  self._get_server(data.get('guild_id'))
            if server is not None:
                channel_id = data.get('id')
                channel = utils.find(lambda c: c.id == channel_id, server.channels)
                server.channels.remove(channel)
                self._invoke_event('on_channel_delete', channel)
        elif event == 'CHANNEL_UPDATE':
            server = self._get_server(data.get('guild_id'))
            if server is not None:
                channel_id = data.get('id')
                channel = utils.find(lambda c: c.id == channel_id, server.channels)
                channel.update(server=server, **data)
                self._invoke_event('on_channel_update', channel)
        elif event == 'CHANNEL_CREATE':
            is_private = data.get('is_private', False)
            channel = None
            if is_private:
                recipient = User(**data.get('recipient'))
                pm_id = data.get('id')
                channel = PrivateChannel(id=pm_id, user=recipient)
                self.private_channels.append(channel)
            else:
                server = self._get_server(data.get('guild_id'))
                if server is not None:
                    channel = Channel(server=server, **data)
                    server.channels.append(channel)

            self._invoke_event('on_channel_create', channel)
        elif event == 'GUILD_MEMBER_ADD':
            server = self._get_server(data.get('guild_id'))
            member = Member(server=server, deaf=False, mute=False, **data)
            server.members.append(member)
            self._invoke_event('on_member_join', member)
        elif event == 'GUILD_MEMBER_REMOVE':
            server = self._get_server(data.get('guild_id'))
            user_id = data['user']['id']
            member = utils.find(lambda m: m.id == user_id, server.members)
            server.members.remove(member)
            self._invoke_event('on_member_remove', member)
        elif event == 'GUILD_MEMBER_UPDATE':
            server = self._get_server(data.get('guild_id'))
            user_id = data['user']['id']
            member = utils.find(lambda m: m.id == user_id, server.members)
            if member is not None:
                user = data['user']
                member.name = user['username']
                member.discriminator = user['discriminator']
                member.avatar = user['avatar']
                member.roles = []
                # update the roles
                for role in server.roles:
                    if role.id in data['roles']:
                        member.roles.append(role)

                self._invoke_event('on_member_update', member)
        elif event == 'GUILD_CREATE':
            self._add_server(data)
            self._invoke_event('on_server_create', self.servers[-1])
        elif event == 'GUILD_DELETE':
            server = self._get_server(data.get('id'))
            self.servers.remove(server)
            self._invoke_event('on_server_delete', server)

    def _opened(self):
        log.info('Opened at {}'.format(int(time.time())))

    def _closed(self, code, reason=None):
        log.info('Closed with {} ("{}") at {}'.format(code, reason, int(time.time())))
        self._invoke_event('on_disconnect')

    def run(self):
        """Runs the client and allows it to receive messages and events."""
        log.info('Client is being run')
        self.ws.run_forever()

    @property
    def is_logged_in(self):
        """Returns True if the client is successfully logged in. False otherwise."""
        return self._is_logged_in

    def get_channel(self, id):
        """Returns a :class:`Channel` or :class:`PrivateChannel` with the following ID. If not found, returns None."""
        if id is None:
            return None

        for server in self.servers:
            for channel in server.channels:
                if channel.id == id:
                    return channel

        for pm in self.private_channels:
            if pm.id == id:
                return pm

    def start_private_message(self, user):
        """Starts a private message with the user. This allows you to :meth:`send_message` to it.

        Note that this method should rarely be called as :meth:`send_message` does it automatically.

        :param user: A :class:`User` to start the private message with.
        """
        if not isinstance(user, User):
            raise TypeError('user argument must be a User')

        payload = {
            'recipient_id': user.id
        }

        r = requests.post('{}/{}/channels'.format(endpoints.USERS, self.user.id), json=payload, headers=self.headers)
        if is_response_successful(r):
            data = r.json()
            log.debug(request_success_log.format(name='start_private_message', response=r, json=payload, data=data))
            self.private_channels.append(PrivateChannel(id=data['id'], user=user))
        else:
            log.error(request_logging_format.format(name='start_private_message', response=r))

    def send_message(self, destination, content, mentions=True, tts=False):
        """Sends a message to the destination given with the content given.

        The destination could be a :class:`Channel` or a :class:`PrivateChannel`. For convenience
        it could also be a :class:`User`. If it's a :class:`User` or :class:`PrivateChannel` then it
        sends the message via private message, otherwise it sends the message to the channel.

        The content must be a type that can convert to a string through ``str(content)``.

        The mentions must be either an array of :class:`User` to mention or a boolean. If
        ``mentions`` is ``True`` then all the users mentioned in the content are mentioned, otherwise
        no one is mentioned. Note that to mention someone in the content, you should use :meth:`User.mention`.

        :param destination: The location to send the message.
        :param content: The content of the message to send.
        :param mentions: A list of :class:`User` to mention in the message or a boolean. Ignored for private messages.
        :param tts: If ``True``, sends tries to send the message using text-to-speech.
        :return: The :class:`Message` sent or None if error occurred.
        """

        channel_id = ''
        is_private_message = True
        if isinstance(destination, Channel) or isinstance(destination, PrivateChannel):
            channel_id = destination.id
            is_private_message = destination.is_private
        elif isinstance(destination, User):
            found = utils.find(lambda pm: pm.user == destination, self.private_channels)
            if found is None:
                # Couldn't find the user, so start a PM with them first.
                self.start_private_message(destination)
                channel_id = self.private_channels[-1].id
            else:
                channel_id = found.id
        else:
            raise InvalidDestination('Destination must be Channel, PrivateChannel, or User')

        content = str(content)
        mentions = self._resolve_mentions(content, mentions)

        url = '{base}/{id}/messages'.format(base=endpoints.CHANNELS, id=channel_id)
        payload = {
            'content': content,
        }

        if not is_private_message:
            payload['mentions'] = mentions

        if tts:
            payload['tts'] = True

        response = requests.post(url, json=payload, headers=self.headers)
        if is_response_successful(response):
            data = response.json()
            log.debug(request_success_log.format(name='send_message', response=response, json=payload, data=data))
            channel = self.get_channel(data.get('channel_id'))
            message = Message(channel=channel, **data)
            return message
        else:
            log.error(request_logging_format.format(name='send_message', response=response))

    def delete_message(self, message):
        """Deletes a :class:`Message`.

        Your own messages could be deleted without any proper permissions. However to
        delete other people's messages, you need the proper permissions to do so.

        :param message: The :class:`Message` to delete.
        :returns: True if the message was deleted successfully, False otherwise.
        """

        url = '{}/{}/messages/{}'.format(endpoints.CHANNELS, message.channel.id, message.id)
        response = requests.delete(url, headers=self.headers)
        log.debug(request_logging_format.format(name='delete_message', response=response))
        return is_response_successful(response)

    def edit_message(self, message, new_content, mentions=True):
        """Edits a :class:`Message` with the new message content.

        The new_content must be able to be transformed into a string via ``str(new_content)``.

        :param message: The :class:`Message` to edit.
        :param new_content: The new content to replace the message with.
        :param mentions: The mentions for the user. Same as :meth:`send_message`.
        :return: The new edited message or None if an error occurred.
        """

        channel = message.channel
        content = str(new_content)

        url = '{}/{}/messages/{}'.format(endpoints.CHANNELS, channel.id, message.id)
        payload = {
            'content': content
        }

        if not channel.is_private:
            payload['mentions'] = self._resolve_mentions(content, mentions)

        response = requests.patch(url, headers=self.headers, json=payload)
        if is_response_successful(response):
            data = response.json()
            log.debug(request_success_log.format(name='edit_message', response=response, json=payload, data=data))
            return Message(channel=channel, **data)
        else:
            log.error(request_logging_format.format(name='edit_message', response=response))

    def login(self, email, password):
        """Logs in the user with the following credentials and initialises
        the connection to Discord.

        After this function is called, :attr:`is_logged_in` returns True if no
        errors occur.

        :param str email: The email used to login.
        :param str password: The password used to login.
        """

        payload = {
            'email': email,
            'password': password
        }

        r = requests.post(endpoints.LOGIN, json=payload)

        if is_response_successful(r):
            log.info('logging in returned status code {}'.format(r.status_code))
            self.email = email

            body = r.json()
            self.token = body['token']
            self.headers['authorization'] = self.token

            gateway = requests.get(endpoints.GATEWAY, headers=self.headers)
            if not is_response_successful(gateway):
                raise GatewayNotFound()
            self._create_websocket(gateway.json().get('url'), reconnect=False)
            self._is_logged_in = True
        else:
            log.error(request_logging_format.format(name='login', response=r))

    def logout(self):
        """Logs out of Discord and closes all connections."""
        response = requests.post(endpoints.LOGOUT)
        self.ws.close()
        self._is_logged_in = False
        self.keep_alive.stop.set()
        log.debug(request_logging_format.format(name='logout', response=response))

    def logs_from(self, channel, limit=500):
        """A generator that obtains logs from a specified channel.

        Yielding from the generator returns a :class:`Message` object with the message data.

        Example: ::

            for message in client.logs_from(channel):
                if message.content.startswith('!hello'):
                    if message.author == client.user:
                        client.edit_message(message, 'goodbye')


        :param channel: The :class:`Channel` to obtain the logs from.
        :param limit: The number of messages to retrieve.
        """

        url = '{}/{}/messages'.format(endpoints.CHANNELS, channel.id)
        params = {
            'limit': limit
        }
        response = requests.get(url, params=params, headers=self.headers)
        if is_response_successful(response):
            messages = response.json()
            log.info('logs_from: {0.url} was successful'.format(response))
            for message in messages:
                yield Message(channel=channel, **message)
        else:
            log.error(request_logging_format.format(name='logs_from', response=response))

    def event(self, function):
        """A decorator that registers an event to listen to.

        You can find more info about the events on the :ref:`documentation below <discord-api-events>`.

        Example: ::

            @client.event
            def on_ready():
                print('Ready!')
        """

        if function.__name__ not in self.events:
            raise InvalidEventName('The function name {} is not a valid event name'.format(function.__name__))

        self.events[function.__name__] = function
        log.info('{0.__name__} has successfully been registered as an event'.format(function))
        return function

    def delete_channel(self, channel):
        """Deletes a channel.

        In order to delete the channel, the client must have the proper permissions
        in the server the channel belongs to.

        :param channel: The :class:`Channel` to delete.
        :returns: True if channel was deleted successfully, False otherwise.
        """

        url = '{}/{}'.format(endpoints.CHANNELS, channel.id)
        response = requests.delete(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='delete_channel'))
        return is_response_successful(response)

    def kick(self, server, user):
        """Kicks a :class:`User` from their respective :class:`Server`.

        You must have the proper permissions to kick a user in the server.

        :param server: The :class:`Server` to kick the member from.
        :param user: The :class:`User` to kick.
        :returns: True if kick was successful, False otherwise.
        """

        url = '{base}/{server}/members/{user}'.format(base=endpoints.SERVERS, server=server.id, user=user.id)
        response = requests.delete(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='kick'))
        return is_response_successful(response)

    def ban(self, server, user):
        """Bans a :class:`User` from their respective :class:`Server`.

        You must have the proper permissions to ban a user in the server.

        :param server: The :class:`Server` to ban the member from.
        :param user: The :class:`User` to ban.
        :returns: True if ban was successful, False otherwise.
        """

        url = '{base}/{server}/bans/{user}'.format(base=endpoints.SERVERS, server=server.id, user=user.id)
        response = requests.put(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='ban'))
        return is_response_successful(response)

    def unban(self, server, name):
        """Unbans a :class:`User` from their respective :class:`Server`.

        You must have the proper permissions to unban a user in the server.

        :param server: The :class:`Server` to unban the member from.
        :param user: The :class:`User` to unban.
        :returns: True if unban was successful, False otherwise.
        """

        url = '{base}/{server}/bans/{user}'.format(base=endpoints.SERVERS, server=server.id, user=user.id)
        response = requests.delete(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='unban'))
        return is_response_successful(response)

    def edit_profile(self, password, **fields):
        """Edits the current profile of the client.

        All fields except password are optional.

        :param password: The current password for the client's account.
        :param new_password: The new password you wish to change to.
        :param email: The new email you wish to change to.
        :param username: The new username you wish to change to.
        """

        payload = {
            'password': password,
            'new_password': fields.get('new_password'),
            'email': fields.get('email', self.email),
            'username': fields.get('username', self.user.name),
            'avatar': self.user.avatar
        }

        url = '{0}/@me'.format(endpoints.USERS)
        response = requests.patch(url, headers=self.headers, json=payload)

        if is_response_successful(response):
            data = response.json()
            log.debug(request_success_log.format(name='edit_profile', response=response, json=payload, data=data))
            self.token = data['token']
            self.email = data['email']
            self.headers['authorization'] = self.token
            self.user = User(**data)
        else:
            log.debug(request_logging_format.format(response=response, name='edit_profile'))

    def edit_channel(self, channel, **options):
        """Edits a :class:`Channel`.

        You must have the proper permissions to edit the channel.

        References pointed to the channel will be updated with the new information.

        :param channel: The :class:`Channel` to update.
        :param name: The new channel name.
        :param position: The new channel's position in the GUI.
        :param topic: The new channel's topic.
        :returns: True if editing was successful, False otherwise.
        """

        url = '{0}/{1.id}'.format(endpoints.CHANNELS, channel)
        payload = {
            'name': options.get('name', channel.name),
            'topic': options.get('topic', channel.topic),
            'position': options.get('position', channel.position)
        }

        response = requests.patch(url, headers=self.headers, json=payload)
        if is_response_successful(response):
            data = response.json()
            log.debug(request_success_log.format(name='edit_channel', response=response, json=payload, data=data))
            channel.update(server=channel.server, **data)
            return True
        else:
            log.debug(request_logging_format.format(response=response, name='edit_channel'))
            return False

    def create_channel(self, server, name, type='text'):
        """Creates a :class:`Channel` in the specified :class:`Server`.

        Note that you need the proper permissions to create the channel.

        :param server: The :class:`Server` to create the channel in.
        :param name: The channel's name.
        :param type: The type of channel to create. 'text' or 'voice'.
        :returns: The newly created :class:`Channel` if successful, else None.
        """

        payload = {
            'name': name,
            'type': type
        }

        url = '{0}/{1.id}/channels'.format(endpoints.SERVERS, server)
        response = requests.post(url, headers=self.headers, json=payload)
        if is_response_successful(response):
            data = response.json()
            log.debug(request_success_log.format(name='create_channel', response=response, data=data, json=payload))
            channel = Channel(server=server, **data)
            # We don't append it to server.channels because CHANNEL_CREATE handles it for us.
            return channel
        else:
            log.debug(request_logging_format.format(response=response, name='create_channel'))

    def leave_server(self, server):
        """Leaves a :class:`Server`.

        :param server: The :class:`Server` to leave.
        :returns: True if leaving was successful, False otherwise.
        """

        url = '{0}/{1.id}'.format(endpoints.SERVERS, server)
        response = requests.delete(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='leave_server'))
        return is_response_successful(response)

    def create_invite(self, destination, **options):
        """Creates an invite for the destination which could be either a :class:`Server` or :class:`Channel`.

        The available options are:

        :param destination: The :class:`Server` or :class:`Channel` to create the invite to.
        :param max_age: How long the invite should last. If it's 0 then the invite doesn't expire. Defaults to 0.
        :param max_uses: How many uses the invite could be used for. If it's 0 then there are unlimited uses. Defaults to 0.
        :param temporary: A boolean to denote that the invite grants temporary membership (i.e. they get kicked after they disconnect). Defaults to False.
        :param xkcd: A boolean to indicate if the invite URL is human readable. Defaults to False.
        :returns: The :class:`Invite` if creation is successful, None otherwise.
        """

        payload = {
            'max_age': options.get('max_age', 0),
            'max_uses': options.get('max_uses', 0),
            'temporary': options.get('temporary', False),
            'xkcdpass': options.get('xkcd', False)
        }

        url = '{0}/{1.id}/invites'.format(endpoints.CHANNELS, destination)
        response = requests.post(url, headers=self.headers, json=payload)
        if is_response_successful(response):
            data = response.json()
            log.debug(request_success_log.format(name='create_invite', json=payload, response=response, data=data))
            data['server'] = self._get_server(data['guild']['id'])
            channel_id = data['channel']['id']
            data['channel'] = utils.find(lambda ch: ch.id == channel_id, data['server'].channels)
            return Invite(**data)
        else:
            log.debug(request_logging_format.format(response=response, name='create_invite'))

    def accept_invite(self, invite):
        """Accepts an :class:`Invite` or a URL to an invite.

        The URL must be a discord.gg URL. e.g. "http://discord.gg/codehere"

        :param invite: The :class:`Invite` or URL to an invite to accept.
        :returns: True if the invite was successfully accepted, False otherwise.
        """

        destination = None
        if isinstance(invite, Invite):
            destination = invite.id
        else:
            rx = r'(?:https?\:\/\/)?discord\.gg\/(.+)'
            m = re.match(rx, invite)
            if m:
                destination = m.group(1)

        if destination is None:
            return False

        url = '{0}/invite/{1}'.format(endpoints.API_BASE, destination)
        response = requests.post(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='accept_invite'))
        return is_response_successful(response)

    def edit_role(self, server, role):
        """Edits the specified :class:`Role` for the entire :class:`Server`.

        To use this you have to edit the role yourself and then pass it
        to this member function. For example: ::

            server = message.channel.server
            role = find(lambda r: r.name == 'My Cool Role', server.roles)
            role.name = 'My Not So Cool Role'
            role.permissions.can_kick_members = False
            role.permissions.can_ban_members = False
            client.edit_role(server, role)

        Note that you cannot edit the name of the @everyone role as that role is special.

        :param server: The :class:`Server` the role belongs to.
        :param role: The :class:`Role` to edit.
        :return: ``True`` if editing was successful, ``False`` otherwise.
        """

        url = '{0}/{1.id}/roles/{2.id}'.format(endpoints.SERVERS, server, role)

        payload = {
            'name': role.name,
            'permissions': role.permissions.value
        }

        response = requests.patch(url, json=payload, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='edit_role'))
        return is_response_successful(response)

    def delete_role(self, server, role):
        """Deletes the specified :class:`Role` for the entire :class:`Server`.

        Works in a similar matter to :func:`edit_role`.

        :param server: The :class:`Server` the role belongs to.
        :param role: The :class:`Role` to delete.
        :return: ``True`` if deleting was successful, ``False`` otherwise.
        """

        url = '{0}/{1.id}/roles/{2.id}'.format(endpoints.SERVERS, server, role)
        response = requests.delete(url, headers=self.headers)
        log.debug(request_logging_format.format(response=response, name='delete_role'))
        return is_response_successful(response)
Example #24
0
code = ''
write_emergency(code)  #safety log = safe!

#wait 5 seconds

port = '/dev/ttyAMA0'
baud = 115200
serial = serial.Serial(port, baud, timeout=0.6)

host = config.get('socket', 'host')
port = config.get('socket', 'port')

ws = WebSocketClient('ws://' + host + ':' + port + '/',
                     protocols=['http-only', 'chat'])
ws.connect()

print "Connected to socket"

while True:

    if (GPIO.input(2) == GPIO.LOW):
        #Pin is set as low, switch to emergency mode!
        if not emergency:
            #read status

            serial.flushInput()
            serial.write("M730\r\n")
            #time.sleep(0.5)
            reply = serial.readline()
Example #25
0
 def connect(self):
     try:
         return WebSocketClient.connect(self)
     except:
         raise ConnectionError()
Example #26
0
    def feedRobotDataInThread(self):
        import io
        from ws4py.client.threadedclient import WebSocketClient
        import json

        camClient = WebSocketClient('ws://localhost:9090/camPub')
        camClient.connect()

        r3dClient = WebSocketClient('ws://localhost:9090/3dPub')
        r3dClient.connect()

        print('Starting data feed')
        while True:
            if self._robot is None:
                print('No robot')
                time.sleep(0.1)
                continue
            # Feed camera
            image = self._robot.world.latest_image
            if image is None:
                print('No image')
                time.sleep(0.1)
                continue
            fobj = io.BytesIO()
            image.raw_image.save(fobj, format="jpeg")
            fobj.seek(0)
            binaryImage = fobj.read()
            if binaryImage is None:
                continue
            camClient.send(binaryImage, binary=True)

            # Feed robot data
            def getData(pose):
                # Don't fail if one of the cubes has flat battery.
                if not pose:
                    return {'x': 0, 'y': 0, 'z': 0, 'rot': (0, 0, 0, 0)}
                pos = pose.position
                rot = pose.rotation
                return {
                    'x': pos.x,
                    'y': pos.y,
                    'z': pos.z,
                    'rot': rot.q0_q1_q2_q3
                }

            def getCubeData(num):
                cube = self._robot.world.light_cubes.get(num)
                data = getData(cube.pose)
                data['seen'] = self.getCubeSeen(num)
                data['visible'] = self.getCubeIsVisible(num)
                return data

            data = {
                'cozmo': getData(self._robot.pose),
                'cubes': [getCubeData(1),
                          getCubeData(2),
                          getCubeData(3)]
            }
            r3dClient.send(json.dumps(data))
            # Sleep a while
            time.sleep(0.1)
Example #27
0
usb_folder = config.get('system', 'usb_folder') 

'''#### LOG ####'''
log_file=config.get('monitor', 'log_file')
logging.basicConfig(filename=log_file,level=logging.INFO,format='%(message)s')

'''### READ PRINTER SETTINGS ###'''
json_f = open(config.get('printer', 'settings_file'))
units = json.load(json_f)

'''#### WEB SOCKET CLIENT ####'''
host=config.get('socket', 'host')
port=config.get('socket', 'port')
try:
    ws = WebSocketClient('ws://'+host +':'+port+'/')
    ws.connect();
    SOCKET_CONNECTED = True
except Exception as inst:
    print inst
    SOCKET_CONNECTED = False



'''#### SETTING GPIO ####'''
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(2, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)


def killAndRaise():
    '''
# Autre TechLab - Core functionality for the Blockly and Ros2

import rclpy
from rclpy.node import Node
import os
import time

from ws4py.client.threadedclient import WebSocketClient
#
blocksClient = WebSocketClient('ws://localhost:8080/blocksPub')
blocksClient.connect()

def start(port=8080):
	blocksClient = WebSocketClient('ws://localhost:' + str(port)+ '/blocksPub')
	blocksClient.connect()


def highlight(block, AtlDebugLevel = 0):  #defined in ../atlide-blockly/js/code.js and ../nodejs/headless.js
	try:
		blocksClient.send(block)
	except:
		get_logger("atlide_core.highlight").info("Ups, cannot send message!!")
		pass
	from rclpy.node import get_logger
	get_logger("atlide_core.highlight").info(str(block) + " " + str(AtlDebugLevel))
	if AtlDebugLevel == 1:
		time.sleep(1)
	if AtlDebugLevel == 2:
		time.sleep(2)
	if AtlDebugLevel == 3:
		time.sleep(5)
def hack_test_4_1_2(n_topics=10):
    # test 'globals'
    subLock = threading.Lock()
    subscriptions = dict()
    def received_message(m):
        data = json.loads(m.data)
        if data['op'] == 'publish':
            r_topic = data['topic']
            r_msg = json.dumps(data['msg'])
#             print data
#             print data.keys()

            with subLock:
                for sub in subscriptions.itervalues():
                    if r_topic == sub['topic']:
                        sub['callback'](r_msg)

    w_type = 2
    if w_type==1:
        ws = WebSocketClient(ROSBRIDGE_HOST)
    elif w_type==2:
        ws = WebSocketClient(ROSBRIDGE_HOST)
        ws.received_message = received_message
#     elif w_type==3:
#         ws = WebSocketClient(ROSBRIDGE_HOST)
#         def received_message(self, m):
#             data = json.loads(m.data)
#             if data['op'] == 'publish':
#                 r_topic = data['topic']
#                 r_msg = json.dumps(data['msg'])
# 
#                 self.subLock.acquire(True)
#                 for sub in self.subscriptions.itervalues():
#                     if r_topic == sub['topic']:
#                         sub['callback'](r_msg)
#                 self.subLock.release()
# #         ws.received_message = received_message
    else:
        ws = RosBridgeClient(ROSBRIDGE_HOST)


    ws.connect()

#     subLock = threading.Lock()
#     subscriptions = dict()
    current_subID = 1
    for i_top in xrange(n_topics):
        # RUN: One Topic (per topic code)
        topicArrived = threading.Event()
        topicArrived.clear()
        def genf(i_topic=0):
            return lambda data: topicArrived.set()

    #     subID = ws.subscribe(SUBTOPIC, MSGTYPE, genf())
        def subscribe(current_subID, topic, messageType, callback):
            subID = current_subID
            current_subID += 1
            msg = {'op': 'subscribe', 'topic': SUBTOPIC,
                   'type': MSGTYPE, 'id': subID, 'throttle_rate': 5}
            ws.send(json.dumps(msg))
            with subLock:
                subscriptions[subID] = {'callback': callback, 'topic': SUBTOPIC}
            return subID
        subID = subscribe(current_subID, SUBTOPIC, MSGTYPE, genf(i_top))

        got_msg = topicArrived.wait(2.0)

    #     ws.unsubscribe(subID)
        def unsubscribe(subID):
            msg = {'op': 'unsubscribe', 'id': subID, 'topic': SUBTOPIC}
            with subLock:
                del subscriptions[subID]
            ws.send(json.dumps(msg))
        unsubscribe(subID)

    ws.close()
class ThreadedClientTest(unittest.TestCase):

    @patch('ws4py.client.socket')
    def setUp(self, sock):
        self.sock = MagicMock(spec=socket.socket)
        sock.socket.return_value = self.sock
        sock.getaddrinfo.return_value = [(socket.AF_INET, socket.SOCK_STREAM, 0, "",
                                          ("127.0.0.1", 80, 0, 0))]

        self.client = WebSocketClient(url="ws://127.0.0.1/")

    def _exchange1(self, *args, **kwargs):
        yield b"\r\n".join([
            b"HTTP/1.1 101 Switching Protocols",
            b"Connection: Upgrade",
            b"Sec-Websocket-Version: 13",
            b"Content-Type: text/plain;charset=utf-8",
            b"Sec-Websocket-Accept: " + b64encode(sha1(self.client.key + WS_KEY).digest()),
            b"Upgrade: websocket",
            b"Date: Sun, 26 Jul 2015 12:32:55 GMT",
            b"Server: ws4py/test",
            b"\r\n"
        ])

        for i in range(100):
            time.sleep(0.1)
            yield Frame(opcode=OPCODE_TEXT, body=b'hello',
                        fin=1).build()

    def _exchange2(self, *args, **kwargs):
        yield Frame(opcode=OPCODE_CLOSE, body=b'',
                    fin=1).build()

    def test_thread_is_started_once_connected(self):
        self.sock.recv.side_effect = self._exchange1()
        self.assertFalse(self.client._th.is_alive())

        self.client.connect()
        time.sleep(0.5)
        self.assertTrue(self.client._th.is_alive())

        self.sock.recv.side_effect = self._exchange2()
        time.sleep(0.5)
        self.assertFalse(self.client._th.is_alive())

    def test_thread_is_started_once_connected_secure(self):
        """ Same as the above test, but with SSL socket """
        # pretend the socket is an SSL socket
        self.sock.pending = lambda: False
        self.client._is_secure = True

        self.sock.recv.side_effect = self._exchange1()
        self.assertFalse(self.client._th.is_alive())

        self.client.connect()
        time.sleep(0.5)
        self.assertTrue(self.client._th.is_alive())

        self.sock.recv.side_effect = self._exchange2()
        time.sleep(0.5)
        self.assertFalse(self.client._th.is_alive())
Example #31
0
class CozmoBot:
    def __init__(self, aruco):
        self._wsClient = None
        self._dataPubThread = None
        # Empty object.
        self._robot = type('', (), {})()
        self._robot.pose = pose_z_angle(0, 0, 0, degrees(0))
        self._aruco = aruco

    def start(self, code):
        from ws4py.client.threadedclient import WebSocketClient

        self._wsClient = WebSocketClient('ws://localhost:9090/WsPub')
        self._wsClient.connect()

        if self._aruco:
            self._dataPubThread = threading.Thread(
                target=self.feedRobotDataInThread)
            self._dataPubThread.daemon = True
            self._dataPubThread.start()

        bot = self

        import cozmo
        exec(code, locals(), locals())

    def feedRobotDataInThread(self):
        print('Starting data feed')
        while True:
            data = {'aruco': self._aruco.getMarkers()}
            self._wsClient.send(json.dumps(data))
            # Sleep a while
            time.sleep(0.1)

    def _update3d(self):
        # Feed robot data
        def getData(pose):
            if not pose:
                return {'x': 0, 'y': 0, 'z': 0, 'rot': (0, 0, 0, 0)}
            pos = pose.position
            rot = pose.rotation.q0_q1_q2_q3
            return {'x': pos.x, 'y': pos.y, 'z': pos.z, 'rot': rot}

        def getCubeData():
            data = getData(None)
            data['seen'] = False
            data['visible'] = False
            return data

        data = {
            'cozmo': getData(self._robot.pose),
            'cubes': [getCubeData(),
                      getCubeData(),
                      getCubeData()]
        }
        self._wsClient.send(json.dumps(data))

    def resetCustomObjects(self):
        pass

    def playAnimation(self, animation):
        pass

    def playEmotion(self, emotion):
        pass

    def lift(self, height):
        pass

    def head(self, angle):
        pass

    def getCubeNumber(self, cube):
        return cozmo.objects.LightCube1Id

    def getCubeSeen(self, cube_num):
        return False

    def getCubeIsVisible(self, cube_num):
        return False

    def getDistanceToCube(self, cube_num):
        return 100000

    def getDistanceBetweenCubes(self, cube1_num, cube2_num):
        return 100000

    def pickupCube(self, cube_num):
        return True

    def placeCubeOnGround(self, cube_num):
        return True

    def placeCubeOnCube(self, other_cube_num):
        return True

    def gotoOrigin(self):
        res = self._robot.go_to_pose(self._origin).wait_for_completed()
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def say(self, text):
        return True

    def enableFreeWill(self, enable):
        return True

    def stop(self):
        pass

    def delay(self, seconds):
        time.sleep(seconds)

    def turn(self, angle):
        '''
		Pretends to take 2 seconds per 180 degrees, with 10 iterations per second.
		'''
        finalAngle = self._robot.pose.rotation.angle_z.degrees + angle
        iterations = abs(int(angle / 180.0 * 2 / 0.1))
        if iterations == 0:
            return
        section = angle / iterations
        for i in range(iterations):
            self._robot.pose._rotation = rotation_z_angle(
                degrees(self._robot.pose.rotation.angle_z.degrees + section))
            self._update3d()
            time.sleep(0.1)
        self._robot.pose._rotation = rotation_z_angle(degrees(finalAngle))
        self._update3d()

    def turnTowardCube(self, cube_num):
        return True

    def driveDistanceWithSpeed(self, distance, speed):
        finalX = self._robot.pose.position.x + math.cos(
            self._robot.pose.rotation.angle_z.radians) * distance * 10
        finalY = self._robot.pose.position.y + math.sin(
            self._robot.pose.rotation.angle_z.radians) * distance * 10
        iterations = abs(int(distance / speed / 0.1))
        sectionX = (finalX - self._robot.pose.position.x) / iterations
        sectionY = (finalY - self._robot.pose.position.y) / iterations
        for i in range(iterations):
            self._robot.pose._position._x = self._robot.pose.position.x + sectionX
            self._robot.pose._position._y = self._robot.pose.position.y + sectionY
            self._update3d()
            time.sleep(0.1)
        self._robot.pose._position._x = finalX
        self._robot.pose._position._y = finalY
        self._update3d()

    def driveWheelsWithSpeed(self, lSpeed, rSpeed):
        pass

    def driveTo(self, x, y):
        distX = x - self._robot.pose.position.x / 10.0
        distY = y - self._robot.pose.position.y / 10.0
        angleRad = math.atan2(distY, distX)
        angleDeg = angleRad * 180 / math.pi
        print(angleDeg)
        self.turn(angleDeg - self._robot.pose.rotation.angle_z.degrees)
        dist = math.sqrt(distX * distX + distY * distY)
        self.driveDistanceWithSpeed(dist, 10)

    def waitForTap(self):
        return cozmo.objects.LightCube1Id

    def addStaticObject(self, model, x1, y1, x2, y2, depth, height):
        data = {
            'addStaticObject': {
                'model': model,
                'x1': x1,
                'y1': y1,
                'x2': x2,
                'y2': y2,
                'depth': depth,
                'height': height
            }
        }
        self._wsClient.send(json.dumps(data))

    def setCubeModel(self, model, num):
        data = {'setCubeModel': {'model': model, 'cubeNum': num}}
        self._wsClient.send(json.dumps(data))

    def highlight(self, block):
        data = {'highlight': block}
Example #32
0
class CozmoBot:
    def __init__(self, aruco):
        self._robot = None
        self._origin = None
        self._dataPubThread = None
        self._camClient = None
        self._wsClient = None
        self._aruco = aruco

    def start(self, code):
        def run(sdk_conn):
            '''The run method runs once Cozmo SDK is connected.'''
            self._robot = sdk_conn.wait_for_robot()
            self._origin = self._robot.pose
            self.cubes_to_numbers = {}
            for key in self._robot.world.light_cubes:
                self.cubes_to_numbers[self._robot.world.light_cubes.get(
                    key).object_id] = key
            self.resetCubes()
            self.resetCustomObjects()

            self._robot.camera.image_stream_enabled = True

            bot = self

            import cozmo
            exec(code, locals(), locals())

        from ws4py.client.threadedclient import WebSocketClient
        self._camClient = WebSocketClient('ws://localhost:9090/camPub')
        self._camClient.connect()

        self._wsClient = WebSocketClient('ws://localhost:9090/WsPub')
        self._wsClient.connect()

        self._dataPubThread = threading.Thread(
            target=self.feedRobotDataInThread)
        self._dataPubThread.daemon = True
        self._dataPubThread.start()

        cozmo.setup_basic_logging()
        cozmo.robot.Robot.drive_off_charger_on_connect = False
        cozmo.connect(run)
        self._robot = None

    def feedRobotDataInThread(self):
        print('Starting data feed')
        while True:
            if self._robot is None:
                print('No robot')
                time.sleep(0.1)
                continue
            # Feed camera
            image = self._robot.world.latest_image
            if image is None:
                print('No image')
                time.sleep(0.1)
                continue
            fobj = io.BytesIO()
            image.raw_image.save(fobj, format="jpeg")
            fobj.seek(0)
            binaryImage = fobj.read()
            if binaryImage is None:
                continue
            self._camClient.send(binaryImage, binary=True)

            # Feed robot data
            def getData(pose):
                # Don't fail if one of the cubes has flat battery.
                if not pose:
                    return {'x': 0, 'y': 0, 'z': 0, 'rot': (0, 0, 0, 0)}
                pos = pose.position - self._origin.position
                rot = quaternion.div(pose.rotation.q0_q1_q2_q3,
                                     self._origin.rotation.q0_q1_q2_q3)
                return {'x': pos.x, 'y': pos.y, 'z': pos.z, 'rot': rot}

            def getCubeData(num):
                cube = self._robot.world.light_cubes.get(num)
                data = getData(cube.pose)
                data['seen'] = self.getCubeSeen(num)
                data['visible'] = self.getCubeIsVisible(num)
                return data

            data = {
                'cozmo': getData(self._robot.pose),
                'cubes': [getCubeData(1),
                          getCubeData(2),
                          getCubeData(3)]
            }
            self._wsClient.send(json.dumps(data))
            # Sleep a while
            time.sleep(0.1)

    def resetCubes(self):
        '''
		Resets position of all cubes to make them "not yet seen".
		'''
        for key in self._robot.world.light_cubes:
            cube = self._robot.world.light_cubes.get(key)
            # Don't fail if one of the cubes has flat battery.
            if cube.pose:
                cube.pose._position = Position(0, 0, 0)

    def resetCustomObjects(self):
        self._robot.world.delete_all_custom_objects()

    def playAnimation(self, animation):
        self._robot.play_anim_trigger(animations[animation],
                                      in_parallel=False).wait_for_completed()

    def playEmotion(self, emotion):
        self._robot.play_anim_trigger(emotions[emotion],
                                      in_parallel=False).wait_for_completed()

    def lift(self, height):
        '''
		height - float, 0=bottom to 1=top
		'''
        self._robot.set_lift_height(height).wait_for_completed()

    def head(self, angle):
        '''
		angle - degrees (low=-25, high=44.5)
		'''
        self._robot.set_head_angle(degrees(angle)).wait_for_completed()

    def getCubeNumber(self, cube):
        return self.cubes_to_numbers.get(cube.object_id)

    def getCubeSeen(self, cube_num):
        '''
		Returns whether cube has been seen since program start.
		'''
        cube = self._robot.world.light_cubes[cube_num]
        if cube.pose:
            pos = cube.pose.position.x_y_z
            return not (pos == (0.0, 0.0, 0.0))
        else:
            return False

    def getCubeIsVisible(self, cube_num):
        '''
		Returns whether cube is visible (in the view).
		'''
        cube = self._robot.world.light_cubes[cube_num]
        if cube:
            return cube.is_visible
        else:
            return False

    def getDistanceToCube(self, cube_num):
        '''
		Returns the distance to the cube if it has been seen since the program start, or 100000 otherwise.
		'''
        if not self.getCubeSeen(cube_num):
            return 100000
        cube = self._robot.world.light_cubes[cube_num]
        pos = self._robot.pose.position - cube.pose.position
        dist = math.sqrt(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z) / 10.0
        return dist

    def getDistanceBetweenCubes(self, cube1_num, cube2_num):
        '''
		Returns the distance between two cubes if both have been seen since the program start, or 100000 otherwise.
		'''
        if not self.getCubeSeen(cube1_num) or not self.getCubeSeen(cube2_num):
            return 100000
        cube1 = self._robot.world.light_cubes[cube1_num]
        cube2 = self._robot.world.light_cubes[cube2_num]
        pos = cube1.pose.position - cube2.pose.position
        dist = math.sqrt(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z) / 10.0
        return dist

    def pickupCube(self, cube_num):
        '''
		Now this is tricky because the action is quite unreliable.
		'''
        # Ignore if cube has not been observed yet.
        if not self.getCubeSeen(cube_num):
            print(
                "[Bot] Ignoring pickupCube() as the cube has not been observed yet"
            )
            return False
        cube = self._robot.world.light_cubes[cube_num]
        # res = self._robot.pickup_object(cube).wait_for_completed()
        # print('pickupCube res:', res)
        res = None
        while res == None or (res.state == cozmo.action.ACTION_FAILED and
                              res.failure_reason[1] in ["repeat", "aborted"]):
            # while res == None or res.state == cozmo.action.ACTION_FAILED:
            res = self._robot.pickup_object(cube).wait_for_completed()
            print('pickupCube res:', res)
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def placeCubeOnGround(self, cube_num):
        if not self.getCubeSeen(cube_num):
            print(
                "[Bot] Ignoring placeCubeOnGround() as the cube has not been observed yet"
            )
            return False
        cube = self._robot.world.light_cubes[cube_num]
        res = self._robot.place_object_on_ground_here(
            cube).wait_for_completed()
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def placeCubeOnCube(self, other_cube_num):
        '''
		Another unreliable action.
		'''
        if not self.getCubeSeen(other_cube_num):
            print(
                "[Bot] Ignoring placeCubeOnCube() as the cube has not been observed yet"
            )
            return False
        print("[Bot] Executing placeCubeOnCube()")
        cube = self._robot.world.light_cubes[other_cube_num]
        # while res == None or (res.state == cozmo.action.ACTION_FAILED and res.failure_code in ["repeat", "aborted"]):
        # 	res = self._robot.go_to_object(cube, distance_mm(100)).wait_for_completed()
        # 	print(res)
        # if res.state == cozmo.action.ACTION_SUCCEEDED:
        # 	res = None
        res = None
        while res == None or (res.state == cozmo.action.ACTION_FAILED
                              and res.failure_code in ["repeat", "aborted"]):
            res = self._robot.place_on_object(cube).wait_for_completed()
            print(res)
        print("[Bot] placeCubeOnCube() finished")
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def gotoOrigin(self):
        res = self._robot.go_to_pose(self._origin).wait_for_completed()
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def say(self, text):
        print("[Bot] Executing Say: " + text)
        res = self._robot.say_text(text).wait_for_completed()
        print("[Bot] Say finished")
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def enableFreeWill(self, enable):
        print("[Bot] Executing enableFreeWill(" + str(enable) + ")")
        if enable:
            self._robot.start_freeplay_behaviors()
        else:
            self._robot.stop_freeplay_behaviors()

    def stop(self):
        print("[Bot] Executing stop")
        self._robot.stop_all_motors()

    def delay(self, seconds):
        '''
		seconds - can be float for fractions of a second
		'''
        # print("[Bot] Executing delay " + str(seconds))
        time.sleep(seconds)

    def turn(self, angle):
        print("[Bot] Executing turn " + str(angle))
        res = self._robot.turn_in_place(degrees(angle)).wait_for_completed()
        print("[Bot] turn finished")
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def turnTowardCube(self, cube_num):
        if not self.getCubeSeen(cube_num):
            print(
                "[Bot] Ignoring turnTowardCube() as the cube has not been observed yet"
            )
            return False
        print("[Bot] Executing turn toward cube")
        cube = self._robot.world.light_cubes[cube_num]
        pos = self._robot.pose.position - cube.pose.position
        angle = radians(math.atan2(pos.y, pos.x) -
                        math.pi) - self._robot.pose.rotation.angle_z
        res = self._robot.turn_in_place(angle).wait_for_completed()
        print("[Bot] turn finished")
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def driveDistanceWithSpeed(self, distance, speed):
        print("[Bot] Executing driveDistanceSpeed(" + str(distance) + ", " +
              str(speed) + ")")
        res = self._robot.drive_straight(distance_mm(distance * 10),
                                         speed_mmps(speed *
                                                    10)).wait_for_completed()
        print("[Bot] driveDistanceSpeed finished")
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def driveWheelsWithSpeed(self, lSpeed, rSpeed):
        print("[Bot] Executing driveWheelsWithSpeed(" + str(lSpeed) + ", " +
              str(rSpeed) + ")")
        self._robot.drive_wheels(lSpeed * 10, rSpeed * 10)

    def driveTo(self, x, y):
        print("[Bot] Executing driveTo(" + str(x) + ", " + str(y) + ")")
        pose = Pose(x * 10,
                    y * 10,
                    0,
                    angle_z=self._robot.pose.rotation.angle_z)
        res = self._robot.go_to_pose(
            self._origin.define_pose_relative_this(pose)).wait_for_completed()
        print("[Bot] driveTo finished")
        return res.state == cozmo.action.ACTION_SUCCEEDED

    def waitForTap(self):
        print("[Bot] Executing waitForTap()")
        return self._robot.world.wait_for(cozmo.objects.EvtObjectTapped,
                                          timeout=None).obj

    def addStaticObject(self, model, x1, y1, x2, y2, depth, height):
        print("[Bot] Executing addStaticObject({},{},{},{},{},{})".format(
            x1, y1, x2, y2, depth, height))

        data = {
            'addStaticObject': {
                'model': model,
                'x1': x1,
                'y1': y1,
                'x2': x2,
                'y2': y2,
                'depth': depth,
                'height': height
            }
        }
        self._wsClient.send(json.dumps(data))

        X1 = x1 * 10
        Y1 = y1 * 10
        X2 = x2 * 10
        Y2 = y2 * 10
        HEIGHT = height * 10

        DEPTH = depth * 10
        WIDTH = math.sqrt(math.pow(X1 - X2, 2) + math.pow(Y1 - Y2, 2))
        centerX = (X1 + X2) / 2.0
        centerY = (Y1 + Y2) / 2.0
        centerZ = HEIGHT / 2.0
        angle = math.atan2(Y1 - Y2, X1 - X2)
        pose = Pose(centerX, centerY, centerZ, angle_z=radians(angle))
        self._robot.world.create_custom_fixed_object(
            self._origin.define_pose_relative_this(pose), WIDTH, DEPTH, HEIGHT)

    def setCubeModel(self, model, num):
        data = {'setCubeModel': {'model': model, 'cubeNum': num}}
        self._wsClient.send(json.dumps(data))

    def highlight(self, block):
        data = {'highlight': block}
        self._wsClient.send(json.dumps(data))
Example #33
0
class Client(object):
    """Represents a client connection that connects to Discord.
    This class is used to interact with the Discord WebSocket and API.

     .. attribute:: user

         A :class:`User` that represents the connected client. None if not logged in.
     .. attribute:: servers

         A list of :class:`Server` that the connected client has available.
     .. attribute:: private_channels

         A list of :class:`PrivateChannel` that the connected client is participating on.
    """
    def __init__(self, **kwargs):
        self._is_logged_in = False
        self.user = None
        self.servers = []
        self.private_channels = []
        self.token = ''
        self.events = {
            'on_ready': _null_event,
            'on_disconnect': _null_event,
            'on_error': _null_event,
            'on_response': _null_event,
            'on_message': _null_event
        }

        self.ws = WebSocketClient(endpoints.WEBSOCKET_HUB,
                                  protocols=['http-only', 'chat'])

        # this is kind of hacky, but it's to avoid deadlocks.
        # i.e. python does not allow me to have the current thread running if it's self
        # it throws a 'cannot join current thread' RuntimeError
        # So instead of doing a basic inheritance scheme, we're overriding the member functions.

        self.ws.opened = self._opened
        self.ws.closed = self._closed
        self.ws.received_message = self._received_message
        self.ws.connect()

        # the actual headers for the request...
        # we only override 'authorization' since the rest could use the defaults.
        self.headers = {
            'authorization': self.token,
        }

    def _received_message(self, msg):
        response = json.loads(str(msg))
        if response.get('op') != 0:
            return

        self.events['on_response'](response)
        event = response.get('t')
        data = response.get('d')

        if event == 'READY':
            self.user = User(**data['user'])
            guilds = data.get('guilds')

            for guild in guilds:
                guild['roles'] = [role.get('name') for role in guild['roles']]
                guild['members'] = [
                    User(**member['user']) for member in guild['members']
                ]

                self.servers.append(Server(**guild))
                channels = [
                    Channel(server=self.servers[-1], **channel)
                    for channel in guild['channels']
                ]
                self.servers[-1].channels = channels

            for pm in data.get('private_channels'):
                self.private_channels.append(
                    PrivateChannel(id=pm['id'], user=User(**pm['recipient'])))

            # set the keep alive interval..
            self.ws.heartbeat_freq = data.get('heartbeat_interval')

            # we're all ready
            self.events['on_ready']()
        elif event == 'MESSAGE_CREATE':
            channel = self.get_channel(data.get('channel_id'))
            message = Message(channel=channel, **data)
            self.events['on_message'](message)

    def _opened(self):
        print('Opened!')

    def _closed(self, code, reason=None):
        print('closed with ', code, reason)

    def run(self):
        """Runs the client and allows it to receive messages and events."""
        self.ws.run_forever()

    @property
    def is_logged_in(self):
        """Returns True if the client is successfully logged in. False otherwise."""
        return self._is_logged_in

    def get_channel(self, id):
        """Returns a :class:`Channel` or :class:`PrivateChannel` with the following ID. If not found, returns None."""
        if id is None:
            return None

        for server in self.servers:
            for channel in server.channels:
                if channel.id == id:
                    return channel

        for pm in self.private_channels:
            if pm.id == id:
                return pm

    def start_private_message(self, user):
        """Starts a private message with the user. This allows you to :meth:`send_message` to it.

        Note that this method should rarely be called as :meth:`send_message` does it automatically.

        :param user: A :class:`User` to start the private message with.
        """
        if not isinstance(user, User):
            raise TypeError('user argument must be a User')

        payload = {'recipient_id': user.id}

        r = response.post('{}/{}/channels'.format(endpoints.USERS,
                                                  self.user.id),
                          json=payload,
                          headers=self.headers)
        if r.status_code == 200:
            data = r.json()
            self.private_channels.append(
                PrivateChannel(id=data['id'], user=user))

    def send_message(self, destination, content, mentions=True):
        """Sends a message to the destination given with the content given.

        The destination could be a :class:`Channel` or a :class:`PrivateChannel`. For convenience
        it could also be a :class:`User`. If it's a :class:`User` or :class:`PrivateChannel` then it
        sends the message via private message, otherwise it sends the message to the channel.

        The content must be a type that can convert to a string through ``str(content)``.

        The mentions must be either an array of :class:`User` to mention or a boolean. If
        ``mentions`` is ``True`` then all the users mentioned in the content are mentioned, otherwise
        no one is mentioned. Note that to mention someone in the content, you should use :meth:`User.mention`.

        :param destination: The location to send the message.
        :param content: The content of the message to send.
        :param mentions: A list of :class:`User` to mention in the message or a boolean. Ignored for private messages.
        """

        channel_id = ''
        is_private_message = True
        if isinstance(destination, Channel) or isinstance(
                destination, PrivateChannel):
            channel_id = destination.id
            is_private_message = destination.is_private
        elif isinstance(destination, User):
            found = next(
                (pm for pm in self.private_channels if pm.user == destination),
                None)
            if found is None:
                # Couldn't find the user, so start a PM with them first.
                self.start_private_message(destination)
                channel_id = self.private_channels[-1].id
            else:
                channel_id = found.id
        else:
            raise InvalidDestination(
                'Destination must be Channel, PrivateChannel, or User')

        content = str(content)

        if isinstance(mentions, list):
            mentions = [user.id for user in mentions]
        elif mentions == True:
            mentions = re.findall(r'@<(\d+)>', content)
        else:
            mentions = []

        url = '{base}/{id}/messages'.format(base=endpoints.CHANNELS,
                                            id=channel_id)
        payload = {
            'content': content,
        }

        if not is_private_message:
            payload['mentions'] = mentions

        response = requests.post(url, json=payload, headers=self.headers)

    def login(self, email, password):
        """Logs in the user with the following credentials.

        After this function is called, :attr:`is_logged_in` returns True if no
        errors occur.

        :param str email: The email used to login.
        :param str password: The password used to login.
        """

        payload = {'email': email, 'password': password}

        r = requests.post(endpoints.LOGIN, json=payload)

        if r.status_code == 200:
            body = r.json()
            self.token = body['token']
            self.headers['authorization'] = self.token
            second_payload = {
                'op': 2,
                'd': {
                    'token': self.token,
                    'properties': {
                        '$os': sys_platform,
                        '$browser': 'pydiscord',
                        '$device': 'pydiscord',
                        '$referrer': '',
                        '$referring_domain': ''
                    }
                }
            }

            self.ws.send(json.dumps(second_payload))
            self._is_logged_in = True

    def event(self, function):
        """A decorator that registers an event to listen to.

        You can find more info about the events on the :ref:`documentation below <discord-api-events>`.

        Example: ::

            @client.event
            def on_ready():
                print('Ready!')
        """

        if function.__name__ not in self.events:
            raise InvalidEventName(
                'The function name {} is not a valid event name'.format(
                    function.__name__))

        self.events[function.__name__] = function
        return function
Example #34
0
 def connect(self, *args, **kwargs):
     self.pre_connect()
     WebSocketClient.connect(self, *args, **kwargs)
     self.connected = True
Example #35
0
class Client(object):
    """Represents a client connection that connects to Discord.
    This class is used to interact with the Discord WebSocket and API.

    A number of options can be passed to the :class:`Client` via keyword arguments.

    :param int max_length: The maximum number of messages to store in :attr:`messages`. Defaults to 5000.

    Instance attributes:

     .. attribute:: user

         A :class:`User` that represents the connected client. None if not logged in.
     .. attribute:: servers

         A list of :class:`Server` that the connected client has available.
     .. attribute:: private_channels

         A list of :class:`PrivateChannel` that the connected client is participating on.
     .. attribute:: messages

        A deque_ of :class:`Message` that the client has received from all servers and private messages.

    .. _deque: https://docs.python.org/3.4/library/collections.html#collections.deque
    """

    def __init__(self, **kwargs):
        self._is_logged_in = False
        self.user = None
        self.servers = []
        self.private_channels = []
        self.token = ''
        self.messages = deque([], maxlen=kwargs.get('max_length', 5000))
        self.events = {
            'on_ready': _null_event,
            'on_disconnect': _null_event,
            'on_error': _null_event,
            'on_response': _null_event,
            'on_message': _null_event,
            'on_message_delete': _null_event
        }

        self.ws = WebSocketClient(endpoints.WEBSOCKET_HUB, protocols=['http-only', 'chat'])

        # this is kind of hacky, but it's to avoid deadlocks.
        # i.e. python does not allow me to have the current thread running if it's self
        # it throws a 'cannot join current thread' RuntimeError
        # So instead of doing a basic inheritance scheme, we're overriding the member functions.

        self.ws.opened = self._opened
        self.ws.closed = self._closed
        self.ws.received_message = self._received_message
        self.ws.connect()

        # the actual headers for the request...
        # we only override 'authorization' since the rest could use the defaults.
        self.headers = {
            'authorization': self.token,
        }

    def _received_message(self, msg):
        response = json.loads(str(msg))
        if response.get('op') != 0:
            return

        self.events['on_response'](response)
        event = response.get('t')
        data = response.get('d')

        if event == 'READY':
            self.user = User(**data['user'])
            guilds = data.get('guilds')

            for guild in guilds:
                guild['roles'] = [role.get('name') for role in guild['roles']]
                guild['members'] = [User(**member['user']) for member in guild['members']]

                self.servers.append(Server(**guild))
                channels = [Channel(server=self.servers[-1], **channel) for channel in guild['channels']]
                self.servers[-1].channels = channels

            for pm in data.get('private_channels'):
                self.private_channels.append(PrivateChannel(id=pm['id'], user=User(**pm['recipient'])))

            # set the keep alive interval..
            self.ws.heartbeat_freq = data.get('heartbeat_interval')

            # we're all ready
            self.events['on_ready']()
        elif event == 'MESSAGE_CREATE':
            channel = self.get_channel(data.get('channel_id'))
            message = Message(channel=channel, **data)
            self.events['on_message'](message)
            self.messages.append(message)
        elif event == 'MESSAGE_DELETE':
            channel = self.get_channel(data.get('channel_id'))
            message_id = data.get('id')
            found = next((m for m in self.messages if m.id == message_id), None)
            if found is not None:
                self.events['on_message_delete'](found)
                self.messages.remove(found)

    def _opened(self):
        print('Opened!')

    def _closed(self, code, reason=None):
        print('closed with ', code, reason)

    def run(self):
        """Runs the client and allows it to receive messages and events."""
        self.ws.run_forever()

    @property
    def is_logged_in(self):
        """Returns True if the client is successfully logged in. False otherwise."""
        return self._is_logged_in

    def get_channel(self, id):
        """Returns a :class:`Channel` or :class:`PrivateChannel` with the following ID. If not found, returns None."""
        if id is None:
            return None

        for server in self.servers:
            for channel in server.channels:
                if channel.id == id:
                    return channel

        for pm in self.private_channels:
            if pm.id == id:
                return pm

    def start_private_message(self, user):
        """Starts a private message with the user. This allows you to :meth:`send_message` to it.

        Note that this method should rarely be called as :meth:`send_message` does it automatically.

        :param user: A :class:`User` to start the private message with.
        """
        if not isinstance(user, User):
            raise TypeError('user argument must be a User')

        payload = {
            'recipient_id': user.id
        }

        r = response.post('{}/{}/channels'.format(endpoints.USERS, self.user.id), json=payload, headers=self.headers)
        if r.status_code == 200:
            data = r.json()
            self.private_channels.append(PrivateChannel(id=data['id'], user=user))

    def send_message(self, destination, content, mentions=True):
        """Sends a message to the destination given with the content given.

        The destination could be a :class:`Channel` or a :class:`PrivateChannel`. For convenience
        it could also be a :class:`User`. If it's a :class:`User` or :class:`PrivateChannel` then it
        sends the message via private message, otherwise it sends the message to the channel.

        The content must be a type that can convert to a string through ``str(content)``.

        The mentions must be either an array of :class:`User` to mention or a boolean. If
        ``mentions`` is ``True`` then all the users mentioned in the content are mentioned, otherwise
        no one is mentioned. Note that to mention someone in the content, you should use :meth:`User.mention`.

        :param destination: The location to send the message.
        :param content: The content of the message to send.
        :param mentions: A list of :class:`User` to mention in the message or a boolean. Ignored for private messages.
        """

        channel_id = ''
        is_private_message = True
        if isinstance(destination, Channel) or isinstance(destination, PrivateChannel):
            channel_id = destination.id
            is_private_message = destination.is_private
        elif isinstance(destination, User):
            found = next((pm for pm in self.private_channels if pm.user == destination), None)
            if found is None:
                # Couldn't find the user, so start a PM with them first.
                self.start_private_message(destination)
                channel_id = self.private_channels[-1].id
            else:
                channel_id = found.id
        else:
            raise InvalidDestination('Destination must be Channel, PrivateChannel, or User')

        content = str(content)

        if isinstance(mentions, list):
            mentions = [user.id for user in mentions]
        elif mentions == True:
            mentions = re.findall(r'@<(\d+)>', content)
        else:
            mentions = []

        url = '{base}/{id}/messages'.format(base=endpoints.CHANNELS, id=channel_id)
        payload = {
            'content': content,
        }

        if not is_private_message:
            payload['mentions'] = mentions

        response = requests.post(url, json=payload, headers=self.headers)


    def login(self, email, password):
        """Logs in the user with the following credentials.

        After this function is called, :attr:`is_logged_in` returns True if no
        errors occur.

        :param str email: The email used to login.
        :param str password: The password used to login.
        """

        payload = {
            'email': email,
            'password': password
        }

        r = requests.post(endpoints.LOGIN, json=payload)

        if r.status_code == 200:
            body = r.json()
            self.token = body['token']
            self.headers['authorization'] = self.token
            second_payload = {
                'op': 2,
                'd': {
                    'token': self.token,
                    'properties': {
                        '$os': sys_platform,
                        '$browser': 'pydiscord',
                        '$device': 'pydiscord',
                        '$referrer': '',
                        '$referring_domain': ''
                    }
                }
            }

            self.ws.send(json.dumps(second_payload))
            self._is_logged_in = True

    def event(self, function):
        """A decorator that registers an event to listen to.

        You can find more info about the events on the :ref:`documentation below <discord-api-events>`.

        Example: ::

            @client.event
            def on_ready():
                print('Ready!')
        """

        if function.__name__ not in self.events:
            raise InvalidEventName('The function name {} is not a valid event name'.format(function.__name__))

        self.events[function.__name__] = function
        return function
Example #36
0
class NotifyService(object):
    """
    Notification service. Handles all notification by sending the messages to
    an opened websocket and writing the same messages to a NOTIFY_FILE file as a 
    fallback in case websocket is not supported.
    """
    def __init__(self, WebSocket=None, notify_file=None, config=None):

        self.notify_lock = RLock()

        if not config:
            self.config = ConfigService()
        else:
            self.config = config

        if not notify_file:
            notify_file = self.config.get('general', 'notify_file')

        if not WebSocket:
            SOCKET_HOST = self.config.get('socket', 'host')
            SOCKET_PORT = self.config.get('socket', 'port')
            self.ws = WebSocketClient('ws://' + SOCKET_HOST + ':' +
                                      SOCKET_PORT + '/')
            self.ws.connect()
        else:
            self.ws = WebSocket

        self.notify_file = notify_file

        self.backtrack = int(self.config.get('notify', 'backtrack', 30))
        self.event_id = 0
        self.events = []

    def notify(self, event_type, event_data):

        with self.notify_lock:
            self.__add_event(event_type, event_data)
            self.__send_message(event_type, event_data)

    def get_last(self):
        if self.events:
            return self.events[-1]
        return None

    def __add_event(self, event_type, event_data):
        """
        Add a new event to the event list and write the list to NOTIFY_FILE.
        """
        self.event_id += 1  # Increment the event ID number

        event = {'id': self.event_id, 'type': event_type, 'data': event_data}

        if len(self.events) >= self.backtrack:
            self.events = self.events[1:] + [event]
        else:
            self.events.append(event)

        wrapper = {'events': self.events, 'last_event': event}

        with open(self.notify_file, 'w') as f:
            f.write(json.dumps(wrapper))

    def __send_message(self, type, data):
        """
        Send message to WebSocket server.
        
        :param type: Message type
        :param data: Message data
        :type type: string
        :type data: string
        """
        message = {'type': type, 'data': data}
        self.ws.send(json.dumps(message))
Example #37
0
class VoiceClient(Client):
    def __init__(self, **kwargs):
        self.token = ''

        gateway = requests.get(endpoints.GATEWAY)
        if gateway.status_code != 200:
            raise GatewayNotFound()
        gateway_js = gateway.json()
        url = gateway_js.get('url')
        if url is None:
            raise GatewayNotFound()

        self.ws = WebSocketClient(url, protocols=['http-only', 'chat', 'voice'])

        # this is kind of hacky, but it's to avoid deadlocks.
        # i.e. python does not allow me to have the current thread running if it's self
        # it throws a 'cannot join current thread' RuntimeError
        # So instead of doing a basic inheritance scheme, we're overriding the member functions.

        self.ws.opened = self._opened
        self.ws.closed = self._closed
        self.ws.received_message = self._received_message

        # the actual headers for the request...
        # we only override 'authorization' since the rest could use the defaults.
        self.headers = {
            'authorization': self.token,
        }

    def _closed(self, code, reason=None):
        print('Closed with {} ("{}") at {}'.format(code, reason, int(time.time())))

    def login(self, email, password):
        """Logs in the user with the following credentials and initialises
        the connection to Discord.

        After this function is called, :attr:`is_logged_in` returns True if no
        errors occur.

        :param str email: The email used to login.
        :param str password: The password used to login.
        """

        self.ws.connect()

        payload = {
            'email': email,
            'password': password
        }

        r = requests.post(endpoints.LOGIN, json=payload)

        if r.status_code == 200:
            body = r.json()
            self.token = body['token']
            self.headers['authorization'] = self.token
            second_payload = {
                'op': 4,
                'd': {
                    'token': self.token,
                    'properties': {
                        '$os': '',
                        '$browser': 'discord.py',
                        '$device': 'discord.py',
                        '$referrer': '',
                        '$referring_domain': ''
                    },
                    'v': 2
                }
            }

            self.ws.send(json.dumps(second_payload))

            self._is_logged_in = True

    def _received_message(self, msg):
        response = json.loads(str(msg))

        s = pprint.pformat(response)
        
        event = response.get('t')
        data = response.get('d')

        if event == 'READY':
            with open("test.txt", "w+") as f:
                f.write(s)

            data = response.get('d')
            interval = data.get('heartbeat_interval') / 1000.0
            self.keep_alive = _keep_alive_handler(interval, self.ws)

        else:
            print(s)
Example #38
0
class WebOS(BaseDriver):

    def __init__(self, config, logger, use_numeric_key=False):
        super(WebOS, self).__init__(config, logger, use_numeric_key)
        self.connectEvent = Event()
        self.curID = 0
        self.callbacks = {}
        self.clientKey = None
        self.client = None
        try:
            with open(config['clientKeyFile'], 'r') as clientKeyInput:
                self.clientKey = yaml.load(clientKeyInput)
        except:
            pass

        logger.info('Loaded %s driver', self.__class__.__name__)

    def saveClientKey(self):
        with open(self.config['clientKeyFile'], 'w') as clientKeyOutput:
            yaml.safe_dump(self.clientKey, clientKeyOutput, allow_unicode=True,
                encoding='utf-8')
            clientKeyOutput.close()

    def on_open(self):
        self.connected = True
        if self.clientKey:
            self.config['registerCommand'].update(self.clientKey)
        self.sendCommandRaw('register', self.config['registerCommand'], None,
            False)

    def on_close(self, code, reason=None):
        self.connected = False
        self.connectEvent.clear()
        self.logger.warn('LG TV Connection closed %s, %s', code, reason)

    def on_message(self, data):
        self.logger.debug('Received %s', data)
        message = json.loads(str(data))
        if message['id'] == 'register0':
            if message['type'] == 'error':
                self.logger.error('Connection issue %s', message['error'])
            elif message['type'] == 'registered':
                if not self.clientKey:
                    self.clientKey = message['payload']
                    self.saveClientKey()
                self.connectEvent.set()
        callback = self.callbacks.get(message['id'])
        if callback:
            callback['data'] = message
            callback['event'].set()

    def connect(self):
        try:
            if self.client:
                try:
                    self.client.close()
                except:
                    pass
            self.client = WebSocketClient("ws://" + self.config['hostName'] + ':' +
                str(self.config['port']),  exclude_headers=["Origin"])
            self.client.opened = self.on_open
            self.client.closed = self.on_close
            self.client.received_message = self.on_message
            self.client.sock.settimeout(self.config['timeout'])
            self.client.connect()
            self.connectEvent.wait(self.config['timeout']
                if self.clientKey else self.config['promptTimeout'])
        except:
            pass

    def sendCommandRaw(self, commandName, command, args=None, shouldWait=True):
        if commandName == 'power_on':
            mac = self.config.get('mac')
            if mac is None:
                self.logger.error('Error sending power on command. MAC is not set up')
            else:
                self.logger.debug('Sending wake up command to %s', mac)
                wakeonlan.send_magic_packet(mac)
            return ''
        elif commandName == 'toggle_mute':
            output = self.sendCommandRaw('status', self.config['commands']['status'])

            if 'error' in output:
                return output

            return self.sendCommandRaw('mute', self.config['commands']['mute'],
                False if output['payload']['mute'] else True)

        if not self.connected:
            try:
                self.connect()
            except:
                raise Exception('Driver ' + __name__ +
                    ' cannot connect to device')

        message = {}
        id = str(self.curID)

        if commandName == 'register':
            message['type'] = 'register'
            message['payload'] = command
            id = 'register' + id
        else:
            message['type'] = 'request'

        message['id'] = id

        argKey = command.get('argKey')
        argData = None
        if args is not None:
            if not argKey:
                raise Exception('Command in ' + __name__ +
                    ': ' + commandName + ' isn''t configured for arguments')

            argData = { argKey: args }

        if argData:
            message['payload'] = argData

        if 'uri' in command:
            message['uri'] = 'ssap://' + command['uri']

        self.logger.debug('Sending %s', message)
        self.client.send(json.dumps(message))
        self.curID += 1
        event = Event()
        callback = {
            'event': event,
            'data': {}
        }

        self.callbacks[id] = callback

        if shouldWait:
            event.wait(self.config['timeout'])
            return callback['data']

        return ''

    def process_result(self, commandName, command, result):
        if 'argKey' in command:
            payload = result['output'].get('payload')
            if not payload:
                self.logger.warning("Missing payload for command %s: %s",
                    commandName, result['output'])
                return
            param = payload.get(command['argKey'])
            if param is not None:
                result['result'] = self.paramParser.translate_param(command, param)
Example #39
0
class VoiceClient(Client):
    def __init__(self, **kwargs):
        self.token = ''

        gateway = requests.get(endpoints.GATEWAY)
        if gateway.status_code != 200:
            raise GatewayNotFound()
        gateway_js = gateway.json()
        url = gateway_js.get('url')
        if url is None:
            raise GatewayNotFound()

        self.ws = WebSocketClient(url,
                                  protocols=['http-only', 'chat', 'voice'])

        # this is kind of hacky, but it's to avoid deadlocks.
        # i.e. python does not allow me to have the current thread running if it's self
        # it throws a 'cannot join current thread' RuntimeError
        # So instead of doing a basic inheritance scheme, we're overriding the member functions.

        self.ws.opened = self._opened
        self.ws.closed = self._closed
        self.ws.received_message = self._received_message

        # the actual headers for the request...
        # we only override 'authorization' since the rest could use the defaults.
        self.headers = {
            'authorization': self.token,
        }

    def _closed(self, code, reason=None):
        print('Closed with {} ("{}") at {}'.format(code, reason,
                                                   int(time.time())))

    def login(self, email, password):
        """Logs in the user with the following credentials and initialises
        the connection to Discord.

        After this function is called, :attr:`is_logged_in` returns True if no
        errors occur.

        :param str email: The email used to login.
        :param str password: The password used to login.
        """

        self.ws.connect()

        payload = {'email': email, 'password': password}

        r = requests.post(endpoints.LOGIN, json=payload)

        if r.status_code == 200:
            body = r.json()
            self.token = body['token']
            self.headers['authorization'] = self.token
            second_payload = {
                'op': 4,
                'd': {
                    'token': self.token,
                    'properties': {
                        '$os': '',
                        '$browser': 'discord.py',
                        '$device': 'discord.py',
                        '$referrer': '',
                        '$referring_domain': ''
                    },
                    'v': 2
                }
            }

            self.ws.send(json.dumps(second_payload))

            self._is_logged_in = True

    def _received_message(self, msg):
        response = json.loads(str(msg))

        s = pprint.pformat(response)

        event = response.get('t')
        data = response.get('d')

        if event == 'READY':
            with open("test.txt", "w+") as f:
                f.write(s)

            data = response.get('d')
            interval = data.get('heartbeat_interval') / 1000.0
            self.keep_alive = _keep_alive_handler(interval, self.ws)

        else:
            print(s)
Example #40
0
task_notifications_file=config.get('task', 'notifications_file')

'''### USB DEV FILE ###'''
dev_usb_file = config.get('system', 'dev_usb_file')
dev_path = config.get('system', 'dev_folder') 

'''#### LOG ####'''
log_file=config.get('monitor', 'log_file')
logging.basicConfig(filename=log_file,level=logging.INFO,format='[%(asctime)s] - %(message)s', datefmt='%d/%m/%Y %H:%M:%S')


'''#### WEB SOCKET CLIENT ####'''
host=config.get('socket', 'host')
port=config.get('socket', 'port')
ws = WebSocketClient('ws://'+host +':'+port+'/', protocols=['http-only', 'chat'])
ws.connect();

'''#### SERIAL PORT COMMUNICATION ####'''
serail_port = config.get('serial', 'port')
serail_baud = config.get('serial', 'baud')
serial = serial.Serial(serail_port, serail_baud, timeout=0.6)

'''#### SETTING GPIO ####'''
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(2, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)


def write_emergency(str):        
    safety = open(safety_file, 'w+')
    print >> safety, str
Example #41
0
class Client(object):
    """Represents a client connection that connects to Discord.
    This class is used to interact with the Discord WebSocket and API.

    A number of options can be passed to the :class:`Client` via keyword arguments.

    :param int max_length: The maximum number of messages to store in :attr:`messages`. Defaults to 5000.

    Instance attributes:

     .. attribute:: user

         A :class:`User` that represents the connected client. None if not logged in.
     .. attribute:: servers

         A list of :class:`Server` that the connected client has available.
     .. attribute:: private_channels

         A list of :class:`PrivateChannel` that the connected client is participating on.
     .. attribute:: messages

        A deque_ of :class:`Message` that the client has received from all servers and private messages.

    .. _deque: https://docs.python.org/3.4/library/collections.html#collections.deque
    """

    def __init__(self, **kwargs):
        self._is_logged_in = False
        self.user = None
        self.servers = []
        self.private_channels = []
        self.token = ""
        self.messages = deque([], maxlen=kwargs.get("max_length", 5000))
        self.events = {
            "on_ready": _null_event,
            "on_disconnect": _null_event,
            "on_error": _null_event,
            "on_response": _null_event,
            "on_message": _null_event,
            "on_message_delete": _null_event,
            "on_message_edit": _null_event,
            "on_status": _null_event,
            "on_channel_delete": _null_event,
            "on_channel_create": _null_event,
            "on_member_join": _null_event,
            "on_member_remove": _null_event,
            "on_member_typing": _null_event,
        }

        gateway = requests.get(endpoints.GATEWAY)
        if gateway.status_code != 200:
            raise GatewayNotFound()
        gateway_js = gateway.json()
        url = gateway_js.get("url")
        if url is None:
            raise GatewayNotFound()

        self.ws = WebSocketClient(url, protocols=["http-only", "chat"])

        # this is kind of hacky, but it's to avoid deadlocks.
        # i.e. python does not allow me to have the current thread running if it's self
        # it throws a 'cannot join current thread' RuntimeError
        # So instead of doing a basic inheritance scheme, we're overriding the member functions.

        self.ws.opened = self._opened
        self.ws.closed = self._closed
        self.ws.received_message = self._received_message

        # the actual headers for the request...
        # we only override 'authorization' since the rest could use the defaults.
        self.headers = {"authorization": self.token}

    def _get_message(self, msg_id):
        return next((m for m in self.messages if m.id == msg_id), None)

    def _get_server(self, guild_id):
        return next((s for s in self.servers if s.id == guild_id), None)

    def _get_channel(self, channel_id):
        return next((c for c in server.channels if c.id == channel_id), None)

    def _get_member(self, user_id):
        return next((m for m in server.members if m.id == user_id), None)

    def _resolve_mentions(self, content, mentions):
        if isinstance(mentions, list):
            return [user.id for user in mentions]
        elif mentions == True:
            return re.findall(r"@<(\d+)>", content)
        else:
            return []

    def _invoke_event(self, event_name, *args, **kwargs):
        try:
            self.events[event_name](*args, **kwargs)
        except Exception as e:
            pass

    def _received_message(self, msg):
        response = json.loads(str(msg))
        if response.get("op") != 0:
            return

        self._invoke_event("on_response", response)
        event = response.get("t")
        data = response.get("d")

        if event == "READY":
            self.user = User(**data["user"])
            guilds = data.get("guilds")

            for guild in guilds:
                guild["roles"] = [Role(**role) for role in guild["roles"]]
                members = guild["members"]
                for i, member in enumerate(members):
                    roles = member["roles"]
                    for j, roleid in enumerate(roles):
                        role = next((r for r in guild["roles"] if r.id == roleid), None)
                        if role is not None:
                            roles[j] = role
                    members[i] = Member(**member)

                for presence in guild["presences"]:
                    user_id = presence["user"]["id"]
                    member = next((m for m in members if m.id == user_id), None)
                    if member is not None:
                        member.status = presence["status"]
                        member.game_id = presence["game_id"]

                server = Server(**guild)

                # give all the members their proper server
                for member in server.members:
                    member.server = server

                for channel in guild["channels"]:
                    changed_roles = []
                    permission_overwrites = channel["permission_overwrites"]

                    for overridden in permission_overwrites:
                        # this is pretty inefficient due to the deep nested loops unfortunately
                        role = next((role for role in guild["roles"] if role.id == overridden["id"]), None)
                        if role is None:
                            continue
                        denied = overridden.get("deny", 0)
                        allowed = overridden.get("allow", 0)
                        override = copy.deepcopy(role)

                        # Basically this is what's happening here.
                        # We have an original bit array, e.g. 1010
                        # Then we have another bit array that is 'denied', e.g. 1111
                        # And then we have the last one which is 'allowed', e.g. 0101
                        # We want original OP denied to end up resulting in whatever is in denied to be set to 0.
                        # So 1010 OP 1111 -> 0000
                        # Then we take this value and look at the allowed values. And whatever is allowed is set to 1.
                        # So 0000 OP2 0101 -> 0101
                        # The OP is (base ^ denied) & ~denied.
                        # The OP2 is base | allowed.
                        override.permissions.value = ((override.permissions.value ^ denied) & ~denied) | allowed
                        changed_roles.append(override)

                    channel["permission_overwrites"] = changed_roles
                channels = [Channel(server=server, **channel) for channel in guild["channels"]]
                server.channels = channels
                self.servers.append(server)

            for pm in data.get("private_channels"):
                self.private_channels.append(PrivateChannel(id=pm["id"], user=User(**pm["recipient"])))

            # set the keep alive interval..
            interval = data.get("heartbeat_interval") / 1000.0
            self.keep_alive = _keep_alive_handler(interval, self.ws)

            # we're all ready
            self._invoke_event("on_ready")
        elif event == "MESSAGE_CREATE":
            channel = self.get_channel(data.get("channel_id"))
            message = Message(channel=channel, **data)
            self.events["on_message"](message)
            self.messages.append(message)
        elif event == "MESSAGE_DELETE":
            channel = self.get_channel(data.get("channel_id"))
            message_id = data.get("id")
            found = self._get_message(message_id)
            if found is not None:
                self.events["on_message_delete"](found)
                self.messages.remove(found)
        elif event == "MESSAGE_UPDATE":
            older_message = self._get_message(data.get("id"))
            if older_message is not None:
                # create a copy of the new message
                message = copy.deepcopy(older_message)
                # update the new update
                for attr in data:
                    if attr == "channel_id":
                        continue
                    value = data[attr]
                    if "time" in attr:
                        setattr(message, attr, message._parse_time(value))
                    else:
                        setattr(message, attr, value)
                self._invoke_event("on_message_edit", older_message, message)
                # update the older message
                older_message = message

        elif event == "PRESENCE_UPDATE":
            server = self._get_server(data.get("guild_id"))
            if server is not None:
                status = data.get("status")
                member_id = data["user"]["id"]
                member = next((u for u in server.members if u.id == member_id), None)
                if member is not None:
                    member.status = data.get("status")
                    member.game_id = data.get("game_id")
                    # call the event now
                    self._invoke_event("on_status", member)
        elif event == "USER_UPDATE":
            self.user = User(**data)
        elif event == "CHANNEL_DELETE":
            server = self._get_server(data.get("guild_id"))
            if server is not None:
                channel_id = data.get("id")
                channel = next((c for c in server.channels if c.id == channel_id), None)
                server.channels.remove(channel)
                self._invoke_event("on_channel_delete", channel)
        elif event == "CHANNEL_CREATE":
            is_private = data.get("is_private", False)
            channel = None
            if is_private:
                recipient = User(**data.get("recipient"))
                pm_id = data.get("id")
                channel = PrivateChannel(id=pm_id, user=recipient)
                self.private_channels.append(channel)
            else:
                server = self._get_server(data.get("guild_id"))
                if server is not None:
                    channel = Channel(server=server, **data)
                    server.channels.append(channel)

            self._invoke_event("on_channel_create", channel)
        elif event == "GUILD_MEMBER_ADD":
            server = self._get_server(data.get("guild_id"))
            member = Member(deaf=False, mute=False, **data)
            server.members.append(member)
            self._invoke_event("on_member_join", member)
        elif event == "GUILD_MEMBER_REMOVE":
            server = self._get_server(data.get("guild_id"))
            user_id = data["user"]["id"]
            member = next((m for m in server.members if m.id == user_id), None)
            server.members.remove(member)
            self._invoke_event("on_member_remove", member)
        elif event == "TYPING_START":
            if self.events["on_member_typing"] == _null_event:
                return

            member = self._get_member(data["user_id"])
            channel = self._get_channel(data["channel_id"])
            timestamp = data["timestamp"]
            self._invoke_event("on_member_remove", member, channel, timestamp)
        # elif event == 'VOICE_STATE_UPDATE':
        #   pass
        # else:
        #    print("Unhandled event (%s)" % event)
        #    from pprint import pprint
        #    pprint(response)

    def _opened(self):
        print("Opened at {}".format(int(time.time())))

    def _closed(self, code, reason=None):
        print('Closed with {} ("{}") at {}'.format(code, reason, int(time.time())))
        self._invoke_event("on_disconnect")

    def run(self):
        """Runs the client and allows it to receive messages and events."""
        self.ws.run_forever()

    @property
    def is_logged_in(self):
        """Returns True if the client is successfully logged in. False otherwise."""
        return self._is_logged_in

    def get_channel(self, id):
        """Returns a :class:`Channel` or :class:`PrivateChannel` with the following ID. If not found, returns None."""
        if id is None:
            return None

        for server in self.servers:
            for channel in server.channels:
                if channel.id == id:
                    return channel

        for pm in self.private_channels:
            if pm.id == id:
                return pm

    def start_private_message(self, user):
        """Starts a private message with the user. This allows you to :meth:`send_message` to it.

        Note that this method should rarely be called as :meth:`send_message` does it automatically.

        :param user: A :class:`User` to start the private message with.
        """
        if not isinstance(user, User):
            raise TypeError("user argument must be a User")

        payload = {"recipient_id": user.id}

        r = requests.post("{}/{}/channels".format(endpoints.USERS, self.user.id), json=payload, headers=self.headers)
        if r.status_code == 200:
            data = r.json()
            self.private_channels.append(PrivateChannel(id=data["id"], user=user))

    def send_message(self, destination, content, mentions=True):
        """Sends a message to the destination given with the content given.

        The destination could be a :class:`Channel` or a :class:`PrivateChannel`. For convenience
        it could also be a :class:`User`. If it's a :class:`User` or :class:`PrivateChannel` then it
        sends the message via private message, otherwise it sends the message to the channel.

        The content must be a type that can convert to a string through ``str(content)``.

        The mentions must be either an array of :class:`User` to mention or a boolean. If
        ``mentions`` is ``True`` then all the users mentioned in the content are mentioned, otherwise
        no one is mentioned. Note that to mention someone in the content, you should use :meth:`User.mention`.

        :param destination: The location to send the message.
        :param content: The content of the message to send.
        :param mentions: A list of :class:`User` to mention in the message or a boolean. Ignored for private messages.
        :return: The :class:`Message` sent or None if error occurred.
        """

        channel_id = ""
        is_private_message = True
        if isinstance(destination, Channel) or isinstance(destination, PrivateChannel):
            channel_id = destination.id
            is_private_message = destination.is_private
        elif isinstance(destination, User):
            found = next((pm for pm in self.private_channels if pm.user == destination), None)
            if found is None:
                # Couldn't find the user, so start a PM with them first.
                self.start_private_message(destination)
                channel_id = self.private_channels[-1].id
            else:
                channel_id = found.id
        else:
            raise InvalidDestination("Destination must be Channel, PrivateChannel, or User")

        content = str(content)
        mentions = self._resolve_mentions(content, mentions)

        url = "{base}/{id}/messages".format(base=endpoints.CHANNELS, id=channel_id)
        payload = {"content": content}

        if not is_private_message:
            payload["mentions"] = mentions

        response = requests.post(url, json=payload, headers=self.headers)
        if response.status_code == 200:
            data = response.json()
            channel = self.get_channel(data.get("channel_id"))
            message = Message(channel=channel, **data)
            return message

    def delete_message(self, message):
        """Deletes a :class:`Message`

        A fairly straightforward function.

        :param message: The :class:`Message` to delete.
        """
        url = "{}/{}/messages/{}".format(endpoints.CHANNELS, message.channel.id, message.id)
        response = requests.delete(url, headers=self.headers)

    def edit_message(self, message, new_content, mentions=True):
        """Edits a :class:`Message` with the new message content.

        The new_content must be able to be transformed into a string via ``str(new_content)``.

        :param message: The :class:`Message` to edit.
        :param new_content: The new content to replace the message with.
        :param mentions: The mentions for the user. Same as :meth:`send_message`.
        :return: The new edited message or None if an error occurred."""
        channel = message.channel
        content = str(new_content)

        url = "{}/{}/messages/{}".format(endpoints.CHANNELS, channel.id, message.id)
        payload = {"content": content}

        if not channel.is_private:
            payload["mentions"] = self._resolve_mentions(content, mentions)

        response = requests.patch(url, headers=self.headers, json=payload)
        if response.status_code == 200:
            data = response.json()
            return Message(channel=channel, **data)

    def login(self, email, password):
        """Logs in the user with the following credentials and initialises
        the connection to Discord.

        After this function is called, :attr:`is_logged_in` returns True if no
        errors occur.

        :param str email: The email used to login.
        :param str password: The password used to login.
        """

        self.ws.connect()

        payload = {"email": email, "password": password}

        r = requests.post(endpoints.LOGIN, json=payload)

        if r.status_code == 200:
            body = r.json()
            self.token = body["token"]
            self.headers["authorization"] = self.token
            second_payload = {
                "op": 2,
                "d": {
                    "token": self.token,
                    "properties": {
                        "$os": sys_platform,
                        "$browser": "discord.py",
                        "$device": "discord.py",
                        "$referrer": "",
                        "$referring_domain": "",
                    },
                    "v": 2,
                },
            }

            self.ws.send(json.dumps(second_payload))
            self._is_logged_in = True

    def logout(self):
        """Logs out of Discord and closes all connections."""
        response = requests.post(endpoints.LOGOUT)
        self.ws.close()
        self._is_logged_in = False
        self.keep_alive.cancel()

    def logs_from(self, channel, limit=500):
        """A generator that obtains logs from a specified channel.

        Yielding from the generator returns a :class:`Message` object with the message data.

        Example: ::

            for message in client.logs_from(channel):
                if message.content.startswith('!hello'):
                    if message.author == client.user:
                        client.edit_message(message, 'goodbye')


        :param channel: The :class:`Channel` to obtain the logs from.
        :param limit: The number of messages to retrieve.
        """

        url = "{}/{}/messages".format(endpoints.CHANNELS, channel.id)
        params = {"limit": limit}
        response = requests.get(url, params=params, headers=self.headers)
        if response.status_code == 200:
            messages = response.json()
            for message in messages:
                yield Message(channel=channel, **message)

    def event(self, function):
        """A decorator that registers an event to listen to.

        You can find more info about the events on the :ref:`documentation below <discord-api-events>`.

        Example: ::

            @client.event
            def on_ready():
                print('Ready!')
        """

        if function.__name__ not in self.events:
            raise InvalidEventName("The function name {} is not a valid event name".format(function.__name__))

        self.events[function.__name__] = function
        return function

    def create_channel(self, server, name, type="text"):
        """Creates a channel in the specified server.

        In order to create the channel the client must have the proper permissions.

        :param server: The :class:`Server` to create the channel from.
        :param name: The name of the channel to create.
        :param type: The type of channel to create. Valid values are 'text' or 'voice'.
        :returns: The recently created :class:`Channel`.
        """
        url = "{}/{}/channels".format(endpoints.SERVERS, server.id)
        payload = {"name": name, "type": type}
        response = requests.post(url, json=payload, headers=self.headers)
        if response.status_code == 200:
            channel = Channel(server=server, **response.json())
            return channel

    def delete_channel(self, channel):
        """Deletes a channel.

        In order to delete the channel, the client must have the proper permissions
        in the server the channel belongs to.

        :param channel: The :class:`Channel` to delete.
        """
        url = "{}/{}".format(endpoints.CHANNELS, channel.id)
        response = requests.delete(url, headers=self.headers)