Advertisement
Guest User

Untitled

a guest
Nov 23rd, 2017
194
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.96 KB | None | 0 0
  1. from websocket import create_connection, WebSocket
  2. import requests
  3. import json
  4. import threading
  5. import time
  6. import socket
  7.  
  8. # manage our connection to the discord gateway
  9. class Gateway:
  10.     def __init__(self, token):
  11.         self.api_token = token
  12.         self.alive = True
  13.  
  14.     def run(self):
  15.         # get discord gateway socketurl
  16.         r = json.loads(requests.get("https://discordapp.com/api/gateway?v=6").text)
  17.         gateway_ws_url = r["url"] + "?v=6&encoding=json"   # voice ws url
  18.         print(gateway_ws_url)
  19.         # connect to gateway socket
  20.         self.gws = create_connection(gateway_ws_url)
  21.         # identify with the gateway
  22.         self.gws.send(json.dumps({
  23.             "op": 2,
  24.             "d": {
  25.                 "token": self.api_token,
  26.                 "properties": {
  27.                     "$os": "linux",
  28.                     "$browser": "disco",
  29.                     "$device": "disco"
  30.                 },
  31.                 "compress": False,
  32.                 "large_threshold": 250,
  33.                 "presence": {
  34.                     "afk": False
  35.                 }
  36.             }
  37.         }))
  38.         # now read from the socket and respond accordingly
  39.         while True:
  40.             # consume ready
  41.             self.consume()
  42.  
  43.     def heartbeat(self):
  44.         i = 0
  45.         while i < self.interval / 1000 and self.alive:
  46.             i += 1
  47.             time.sleep(1)
  48.         # send heartbeat
  49.         self.gws.send(json.dumps({
  50.             "op": 1,
  51.             "d": self.s
  52.         }))
  53.  
  54.     # recvs one value from the gateway socket, and processes it accordingly
  55.     def consume(self):
  56.         # get recv data and opcode
  57.         opcode, raw_recv = self.gws.recv_data()
  58.         print(opcode, raw_recv)
  59.         # if we recv a blank string, that means the server disconnected us
  60.         if not raw_recv or raw_recv.strip() == "" or opcode > 1:
  61.             exit("disconnected")
  62.         # parse recv data
  63.         recv = json.loads(raw_recv)
  64.  
  65.         # identify the sent operation and handle it
  66.         if recv["op"] == 10:   # HELLO
  67.             # start a new thread handling heartbeat pulses (ping)
  68.             self.interval = recv["d"]["heartbeat_interval"]
  69.             self.s = recv["s"]
  70.             self.heartbeat_thread = threading.Thread(
  71.                 target=self.heartbeat, args=()
  72.             )
  73.             self.heartbeat_thread.start()
  74.         elif recv["op"] == 11:   # Heartbeat ACK
  75.             # start the next hearbeat thread
  76.             self.heartbeat_thread = threading.Thread(
  77.                 target=self.heartbeat, args=()
  78.             )
  79.             self.heartbeat_thread.start()
  80.         elif recv["op"] == 0:   # DISPATCH
  81.             if recv["t"] == "READY":   # READY
  82.                 # possibly store information
  83.                 self.on_ready(self, recv)
  84.             elif recv["t"] == "GUILD_CREATE":   # GUILD_CREATE
  85.                 # possibly store information
  86.                 pass
  87.             elif recv["t"] == "VOICE_STATE_UPDATE":   # VOICE_STATE_UPDATE
  88.                 self.session_id = recv["d"]["session_id"]
  89.                 self.user_id = recv["d"]["user_id"]
  90.             elif recv["t"] == "VOICE_SERVER_UPDATE":   # VOICE_SERVER_UPDATE
  91.                 self.on_voice_server_update(self, recv)
  92.  
  93.  
  94. # manage our connection to the voice server
  95. class VoiceChat:
  96.     def __init__(self, token, guild_id, channel_id):
  97.         self.guild_id = guild_id
  98.         self.channel_id = channel_id
  99.         gateway = Gateway(token)
  100.         gateway.on_ready = self.on_ready
  101.         gateway.on_voice_server_update = self.on_voice_server_update
  102.         #gateway.run(); return None
  103.         try:
  104.             gateway.run()
  105.         except Exception as e:
  106.             print(e)
  107.             gateway.alive = False
  108.  
  109.     def on_ready(self, gateway, recv):
  110.         # inform the gateway of our intent to establish voice connectivity...
  111.         gateway.gws.send(json.dumps({
  112.             "op": 4,
  113.             "d": {
  114.                 "guild_id": self.guild_id,
  115.                 "channel_id": self.channel_id,
  116.                 "self_mute": False,
  117.                 "self_deaf": False
  118.             }
  119.         }))
  120.  
  121.     def on_voice_server_update(self, gateway, recv):
  122.         # Now we can make the actual voice websocket connection.
  123.         self.endpoint = recv["d"]["endpoint"]
  124.         # remove the port
  125.         self.endpoint = endpoint[:endpoint.find(":")]
  126.         self.vws = create_connection(
  127.             "wss://" + self.endpoint + "?v=3"
  128.         )
  129.         self.alive = True
  130.  
  131.         # identify with the voice server
  132.         self.vws.send(json.dumps({
  133.             "op": 0,
  134.             "d": {
  135.                 "server_id": self.guild_id,   #namecontinuity
  136.                 "user_id": gateway.user_id,
  137.                 "session_id": gateway.session_id,   # just going to assume this is here
  138.                 "token": recv["d"]["token"]
  139.             }
  140.         }))
  141.  
  142.         # start handling the voice socket in a background thread
  143.         self.consume_thread = threading.Thread(
  144.             target=self.consume_forever, args=()
  145.         )
  146.         self.consume_thread.start()
  147.  
  148.     def consume_forever(self):
  149.         while True:
  150.             self.consume()
  151.  
  152.     # handles one packet from the voice chat websocket
  153.     def consume(self):
  154.         # get recv data and opcode
  155.         opcode, raw_recv = self.vws.recv_data()
  156.         print(opcode, raw_recv)
  157.         # if we recv a blank string, that means the server disconnected us
  158.         if not raw_recv or raw_recv.strip() == "" or opcode > 1:
  159.             exit("disconnected")
  160.         # parse recv data
  161.         recv = json.loads(raw_recv)
  162.         if "op" not in recv and "heartbeat_interval" in recv:   # HELLO
  163.             # start a new thread handling heartbeat pulses (ping)
  164.             self.interval = recv["heartbeat_interval"] * 0.75
  165.             self.heartbeat_thread = threading.Thread(
  166.                 target=self.heartbeat, args=()
  167.             )
  168.             self.heartbeat_thread.start()
  169.         elif recv["op"] == 2:   # READY
  170.             self.on_ready(recv)
  171.  
  172.     def heartbeat(self):
  173.         i = 0
  174.         while i < self.interval / 1000 and self.alive:
  175.             i += 1
  176.             time.sleep(1)
  177.         # send heartbeat
  178.         self.gws.send(json.dumps({
  179.             "op": 3,
  180.             "d": i * 314195   # because I don't really understand nonces
  181.         }))
  182.  
  183.     def on_ready(self, recv):
  184.         # create a udp socket to the server
  185.         socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  186.         # send an IP Lookup packet
  187.         packet = bytearray(70)
  188.         struct.pack_into(">I", packet, 0, recv["d"]["ssrc"])
  189.         socket.sendto(packet, (self.endpoint, recv["d"]["ssrc"]))
  190.         recv = socket.recv(70)
  191.         # get the port and host from the udp socket
  192.        
  193.         # send host and port to websocket in exchange for private key
  194.        
  195.  
  196. if __name__ == "__main__":
  197.     v = VoiceChat(
  198.         "authtoken",
  199.         "guildid",
  200.         "channelid"
  201.     )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement