How to send a message to Server with Websocket - python

I'm trying to send messages to a Server to get answers.
I've tried to use official websocket APIs from the site but I don't understand them or can't make them work as I wish, so I'm trying to build it.
import asyncio
import websockets
async def test():
async with websockets.connect('wss://www.bitmex.com/realtime') as websocket:
await websocket.send("ping")
#OR await websocket.send({"op": "subscribe", "args": [<SubscriptionTopic>]})
response = await websocket.recv()
print(response)
asyncio.get_event_loop().run_until_complete(test())
I recieve that I'm connected but I don't recieve "pong" as an answer to "ping", nor "Good you are subscribed to this Topic" as I recieve when trying the commands on a echo website.
#!/usr/bin/env python3
import asyncio
import websockets
import json
var = []
async def test():
async with websockets.connect('wss://www.bitmex.com/realtime') as websocket:
response = await websocket.recv()
print(response)
await websocket.send(json.dumps({"op": "subscribe", "args": "trade:TRXH19"}))
response = await websocket.recv()
resp = await websocket.recv()
print(json.loads(resp))
sum=0
while True:
resp = await websocket.recv()
jj = json.loads(resp)["data"][0]
var.append(jj)
size = jj["size"]
side = jj["side"]
coin = jj["symbol"]
if side=="Buy":
sum+=size
else:
sum-=size
print(coin)
print(size)
print(side)
print("Totale = ", sum )
while True:
asyncio.get_event_loop().run_until_complete(test())
print(var)
print("Ciclo Finito!!!!")

That's because you have to read received data after every send.
#!/usr/bin/env python3
import asyncio
import websockets
import json
var = []
async def test():
async with websockets.connect('wss://www.bitmex.com/realtime') as websocket:
response = await websocket.recv()
print(response)
await websocket.send("ping")
response = await websocket.recv()
print(response)
var.append(response)
await websocket.send(json.dumps({"op": "subscribe", "args": "test"}))
response = await websocket.recv()
print(response)
asyncio.get_event_loop().run_until_complete(test())
print(var)
Output:
{"info":"Welcome to the BitMEX Realtime API.","version":"2019-02-12T19:21:05.000Z","timestamp":"2019-02-17T14:38:32.696Z","docs":"https://www.bitmex.com/app/wsAPI","limit":{"remaining":37}}
pong
{"status":400,"error":"Unknown table: test","meta":{},"request":{"op":"subscribe","args":"test"}}
['pong']
Edit - code with handling websockets fall and multiple data:
#!/usr/bin/env python3
import asyncio
import websockets
import json
total = 0
async def test():
async with websockets.connect('wss://www.bitmex.com/realtime') as websocket:
response = await websocket.recv()
print(response)
await websocket.send(json.dumps({"op": "subscribe", "args": "trade:TRXH19"}))
response = await websocket.recv()
#resp = await websocket.recv()
#print(json.loads(resp))
global total
while True:
resp = await websocket.recv()
print(resp)
for jj in json.loads(resp)["data"]:
size = jj["size"]
side = jj["side"]
coin = jj["symbol"]
if side == "Buy":
total += size
else:
total -= size
print(coin)
print(size)
print(side)
print("Totale = ", total)
while True:
loop = asyncio.new_event_loop()
try:
loop.run_until_complete(test())
except Exception as e:
print(e)
loop.close()
#finally:
print(total)
print("Ciclo Finito!!!!")

Related

Why doesn't this python aiohttp requests code run asynchronously?

I'm trying to access an API with aiohttp but something is causing this code to block each iteration.
def main():
async with aiohttp.ClientSession() as session:
for i, (image, target) in enumerate(dataset_val):
image_bytes = pil_to_bytes(image)
async with session.post('http://localhost:8080/predictions/resnet50', data=image_bytes) as resp:
print(await resp.text())
print(i, flush=True, end='\r')
asyncio.run(main())
As explained by #deceze, await will wait for your result inside your loop. If you want to call everything at the same time, you need to call everything from an external loop and gather the results.
Here's a way of doing it
import asyncio
import aiohttp
async def call(session: aiohttp.ClientSession, url: str, image):
image_bytes = pil_to_bytes(image)
async with session.post(url, data=image_bytes) as response:
return await response.text()
async def call_all(url:str, tasks: list):
async with aiohttp.ClientSession() as session:
results = await asyncio.gather(
*[call(session, url, img) for img, target in tasks],
return_exceptions=True
)
return results
loop = asyncio.get_event_loop()
res = loop.run_until_complete(
call_all('http://localhost:8080/predictions/resnet50', dataset_val)
)

discord.py bot random image from a folder but each file can only be shown once

I'm fairly new to python and I can't seem to figure out how to make this work. any help?
I'm trying to make a command that makes my discord bot display a random image from a folder. There are around 2000 images in the folder. I want everyone to be able to use the command only once. The images are all unique and I don't want people getting the same image. how would I do this?
# Import Discord Package
import discord
from discord.ext import commands
# Client
client = commands.Bot(command_prefix='/')
# Display random image
# Command that shows Mintbot's version
#client.command(name='version')
async def version(context):
myEmbed = discord.Embed(title="Mintbot", description="Test version", color=800080)
myEmbed.add_field(name="Version Code", value="v1.0.0", inline=False)
myEmbed.set_footer(text="Work In Progress!")
await context.message.channel.send(embed=myEmbed)
# Welcome Message
#client.event
async def on_ready():
general_channel = client.get_channel(931259149260554283)
await general_channel.send('Hello, Mintbot here!')
# Disconnect message
#client.event
async def on_disconnect():
general_channel = client.get_channel(931259149260554283)
await general_channel.send('Turning Off')
# Mintbot Version - Embed
#client.event
async def on_message(message):
if message.content == 'what version is mintbot?':
general_channel = client.get_channel(931259149260554283)
myEmbed = discord.Embed(title="Mintbot", description="Test version", color=800080)
myEmbed.add_field(name="Version Code", value="v1.0.0", inline=False)
myEmbed.set_footer(text="Work In Progress!")
await general_channel.send(embed=myEmbed)
await client.process_commands(message)
# Run the client on the server
client.run('mytoken')
Make sure that you have a json file named " list.json ".
import discord
from discord.ext import commands
import os
import json
import random
# Client
client = commands.Bot(command_prefix='/')
# Reading images
directory = "images" # Change this to your folder directory without / on the end
img = []
total_img = -1
for filename in os.listdir(directory):
img += [filename]
total_img += 1
# Display random image
#client.command()
async def image(context):
with open("list.json", "r") as f:
sent = json.load(f)
if not str("sent") in sent:
sent = {}
sent["sent"] = []
with open("list.json", "w") as f:
json.dump(sent, f , indent=4)
with open("list.json", "r") as f:
sent = json.load(f)
if not str(context.author.id) in sent:
sent[str(context.author.id)] = True
with open("list.json", "w") as f:
json.dump(sent, f , indent=4)
data = sent["sent"]
random_number = None
tries = 0
while random_number == None:
tries += 1
number = random.randint(0, total_img)
if not number in data:
random_number = number
if int(tries + 1) == total_img:
await context.send("All pictures has been sent")
return
file = discord.File(f"{directory}/{img[random_number]}")
await context.send(file=file)
sent["sent"] += [random_number]
with open("list.json", "w") as f:
json.dump(sent, f , indent=4)
# Command that shows Mintbot's version
#client.command(name='version')
async def version(context):
myEmbed = discord.Embed(title="Mintbot", description="Test version", color=800080)
myEmbed.add_field(name="Version Code", value="v1.0.0", inline=False)
myEmbed.set_footer(text="Work In Progress!")
await context.message.channel.send(embed=myEmbed)
# Welcome Message
#client.event
async def on_ready():
general_channel = client.get_channel(931259149260554283)
await general_channel.send('Hello, Mintbot here!')
# Disconnect message
#client.event
async def on_disconnect():
general_channel = client.get_channel(931259149260554283)
await general_channel.send('Turning Off')
# Mintbot Version - Embed
#client.event
async def on_message(message):
if message.content == 'what version is mintbot?':
general_channel = client.get_channel(931259149260554283)
myEmbed = discord.Embed(title="Mintbot", description="Test version", color=800080)
myEmbed.add_field(name="Version Code", value="v1.0.0", inline=False)
myEmbed.set_footer(text="Work In Progress!")
await general_channel.send(embed=myEmbed)
await client.process_commands(message)
# Run the client on the server
client.run(token)

Discord Bot embed

Im having a little trouble embeding this for a discord bot i tried some thing but none seem to work.
import os
#bot.command()
async def ping(ctx, *, ipaddr: str = '1.3.3.7'):
ip_list = [ipaddr]
for ip in ip_list:
response = os.popen(f"ping {ip}").read()
if "Received = 4" in response:
await ctx.send(f"UP {ip} / Ping Successful")
else:
await ctx.send(f"DOWN {ip} / Ping Unsuccessful")
NEVER MIND ISSUE WAS FIXED I JUST DID THIS BELOW
#bot.command()
async def ping(ctx, *, ipaddr: str = '1.3.3.7'):
ip_list = [ipaddr]
embed = discord.Embed(title='Ping Info:', color=0xFF0000)
embed.set_footer(text=f"Requested by {ctx.author}")
for ip in ip_list:
response = os.popen(f"ping {ip}").read()
if "Received = 4" in response:
embed.add_field(name=f"{ip} is UP", value="Ping Successful", inline=False)
else:
embed.add_field(name=f"{ip} is DOWN", value="Ping Unsuccessful", inline=False)
await ctx.send(embed=embed)

AttributeError: module 'select' has no attribute 'select' error ASYNCIO

I am executing the below code on a windows pc. I read that, by default, Windows can use only 64 sockets in asyncio loop. I don't know if this is the reason for the error.
import aiohttp
import asyncio
import time
async def download_file(url):
print(f'started downloading{url}')
connector = aiohttp.TCPConnector(limit=60)
async with aiohttp.clientSession(connector) as session:
async with session.get(url) as resp:
content = await resp.read()
print (f'Finished download{url}')
return content
async def write_file(n, content):
filename = f'async_{n}.html'
with open(filename,'wb') as f:
print(f'started writing{filename}')
f.write(content)
print(f'Finished writing{filename}')
async def scrape_task(n,url):
content = await download_file(url)
await write_file(n,content)
async def main():
tasks = []
for n,url in enumerate(open('urls.txt').readlines()):
tasks.append((scrape_task(n, url)))
await asyncio.wait(tasks)
if __name__ == '__main__':
t=time.perf_counter()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
t2 = time.perf_counter() - t
print(f'Total time taken: {t2:0.2f} seconds')
I made the below changes to limit the connections to 60
connector = aiohttp.TCPConnector(limit=60)
async with aiohttp.clientSession(connector) as session:
I can't figure out where I am going wrong.

Discord bot does not accept commands when other command is running

I'm developing a discord bot that can find spotify playlists and queue the tracks' youtube counterparts. I have a loop running that uses a list of tracknames to search for a video on youtube, it then grabs the top result and sends to an asynchronous function that plays it. However, whilst the bot is in this loop it does not accept other commands. Can I make this run concurrently with other commands? The following is all the code of my application
from bs4 import BeautifulSoup
import urllib.request
import os
import requests
import base64
import json
import time
import discord
import shutil
from discord.utils import get
from discord import FFmpegPCMAudio
import youtube_dl
import asyncio
from asgiref.sync import async_to_sync
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(command_prefix='s- ')
accessToken = ""
clientIDSECRET = os.getenv('SPOTIFY_ID')+':'+os.getenv('SPOTIFY_SECRET')
base64Auth = base64.b64encode(clientIDSECRET.encode("utf-8")).decode('ascii')
trackStrings = []
def pretty_print_POST(req):
print('{}\n{}\r\n{}\r\n\r\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
#bot.event
async def on_ready():
payload={'grant_type':'client_credentials'}
headers = {'Authorization':f'Basic {base64Auth}'}
req = requests.Request('POST', "https://accounts.spotify.com/api/token", data = payload, headers = headers)
prep = req.prepare()
pretty_print_POST(prep)
s = requests.Session()
response = s.send(prep)
global accessToken
accessToken = json.loads(response.content)["access_token"]
print(accessToken)
#bot.command(pass_context=True, aliases=['sp'])
async def spotlist(ctx, userName, playlistName = "", shuffle=False, limit=100, offset=0):
print(limit)
if limit > 100 or limit < 0:
await ctx.send(f'Limit out of bounds! It needs to be between 0 and 100.')
return
playlistId = ""
headers = {'Authorization':f'Bearer {accessToken}'}
if playlistName == "id":
playlistId = userName #Username assumed to be a playlist id instead
else:
playlists = json.loads(requests.get(f'https://api.spotify.com/v1/users/{userName}/playlists', headers=headers).content)
for playlist in playlists["items"]:
if playlist["name"] == playlistName:
playlistId = playlist["id"]
nextURL = f'https://api.spotify.com/v1/playlists/{playlistId}/tracks?offset={offset}&limit={limit}'
while nextURL != None:
trackResponse = requests.get(nextURL, headers = headers)
tracks = json.loads(trackResponse.content)
if(tracks["total"] <= offset):
await ctx.send(f'Offset (third argument) is too large! Your playlist is {tracks["total"]} long.')
return
for track in tracks["items"]:
trackStrings.append(track["track"]["name"] + " " + track["track"]["artists"][0]["name"])
nextURL = tracks["next"]
if(limit != 100):
break
for trackString in trackStrings:
try:
await play(ctx, await SearchVid(trackString))
except:
print("couldn't find song")
#bot.command(pass_context=True, aliases=['j', 'joi'])
async def join(ctx):
channel = ctx.message.author.voice.channel
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_connected():
await voice.move_to(channel)
else:
voice = await channel.connect()
#bot.command(pass_context=True, aliases=['l', 'lea'])
async def leave(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_connected():
await voice.disconnect()
else:
await ctx.send("Don't think I am in a voice channel")
async def playSong(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
DIR = os.path.abspath(os.path.realpath("Queue"))
try:
first_file = os.listdir(DIR)[0]
except:
print("No more queued song(s)\n")
return
song_path = os.path.abspath(os.path.realpath("Queue") + "\\" + first_file)
async def func(x):
os.remove(song_path)
await playSong(ctx)
try:
voice.play(discord.FFmpegPCMAudio(song_path), after=async_to_sync(func))
await ctx.send(f"playing {first_file}")
voice.source = discord.PCMVolumeTransformer(voice.source)
voice.source.volume = 0.07
except:
print("song already playing")
still_q = len(os.listdir(DIR))
print(f"Songs still in queue: {still_q}")
#bot.command(pass_context=True, aliases=['p', 'pla'])
async def play(ctx, url: str = ""):
await join(ctx)
Queue_infile = os.path.isdir("./Queue")
if Queue_infile is True:
DIR = os.path.abspath(os.path.realpath("Queue"))
try:
_ = os.listdir(DIR)[0]
except:
print("No more queued song(s)\n")
await queue(ctx, url)
await playSong(ctx)
else:
await queue(ctx, url)
await playSong(ctx)
else:
return
#bot.command(pass_context=True, aliases=['s'])
async def skip(ctx):
await stop(ctx)
#bot.command(pass_context=True, aliases=['pa', 'pau'])
async def pause(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_playing():
print("Music paused")
voice.pause()
await ctx.send("Music paused")
else:
print("Music not playing failed pause")
await ctx.send("Music not playing failed pause")
#bot.command(pass_context=True, aliases=['r', 'res'])
async def resume(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_paused():
print("Resumed music")
voice.resume()
await ctx.send("Resumed music")
else:
print("Music is not paused")
await ctx.send("Music is not paused")
async def stop(ctx):
voice = get(bot.voice_clients, guild=ctx.guild)
if voice and voice.is_playing():
voice.stop()
else:
print("No music playing failed to stop")
async def SearchVid(textToSearch):
print(textToSearch)
query = urllib.parse.quote(textToSearch)
url = "https://www.youtube.com/results?search_query=" + query
response = urllib.request.urlopen(url)
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
for vid in soup.findAll(attrs={'class':'yt-uix-tile-link'}):
if not vid['href'].startswith("https://googleads.g.doubleclick.net/"):
return 'https://www.youtube.com' + vid['href']
async def queue(ctx, url: str):
Queue_infile = os.path.isdir("./Queue")
if Queue_infile is False:
os.mkdir("Queue")
DIR = os.path.abspath(os.path.realpath("Queue"))
q_num = len(os.listdir(DIR))
queue_path = os.path.abspath(os.path.realpath("Queue") + f"\\{q_num} %(title)s.%(ext)s")
print(queue_path)
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': queue_path,
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
print("Downloading audio now\n")
print(url)
ydl.download([url])
name = os.listdir(DIR)[-1]
await ctx.send("Adding song " + str(name) + " to the queue")
print("Song added to queue\n")
bot.run(TOKEN)
I would definitely suggest using the module threading. I do not currently have enough time to read your code and put it in, though I might edit this answer later.
Refer to:
https://docs.python.org/3/library/threading.html
Threading allows you to run multiple functions at once.
You're using blocking libraries. Discord.py is a asynchronous library and you need to use things that don't block your code. In Frequently Asked Questions you can see a example using requests library, that's blocking and you should use aiohttp to make asynchronous requests instead.

Categories