I trying to use websockets to receive real time update on trading orders. If it sent "closed" then to run some function.
The problem is It only run in "one time". I have tried but still in the dark.
EDIT. I try to make it in class but I don't know why I can't pass variable(self.status) to another function pending(self) in same class
class check:
async def handler(self):
async with websockets.connect('wss://ftx.com/ws/') as ws:
# authentication things
async for data in ws:
message = json.loads(data)
search = dictpy.DictSearch(data=message, target='closed')
self.status = search.result
print(self.status) # It contain 'closed'
async def pending(self):
print(self.status) # but It didn't even recieve from handler
if self.status == [['data.status', {'status': 'closed'}]]:
t3.start()
t4.start()
t3.join()
t4.join()
Related
I'm hosting my bot online and sometimes messages take time to edit their own View components which is fine. The problem is when i modify a view by calling
await message.edit(view=...)
, the new button/select components are displayed instantly but their callbacks are not operational because the message editing is taking some time to complete. Thus, unknown interaction error tends to occur when clicking on the button a little too early, the callbacks are not being called, and I need to wait to re-click.
My question is : Is it possible to wait for a message.edit() to fully complete before showing the buttons, or is there another way to solve this issue?
Code sample :
async def throw_dice(self,ctx):
try :
superself = self
async def action(superself):
...
if isinstance(self.current,PlayerDiscord) :
class myButton(ui.Button):
def __init__(self,label,style,row=None):
super().__init__(label=label,style=style,row=row)
async def callback(self,interaction):
await interaction.response.defer()
nonlocal superself
if interaction.user.id==superself.current.member.id:
self.view.stop()
await superself.msg_play.edit(view=None)
await action(superself)
self.view = FRPGame.myView(ctx,self) #Create new view
self.view.add_item(myButton("\U0001F3B2",style=discord.ButtonStyle.primary))
#self.msg_play stores the message
await self.msg_play.edit(content=self.content,view=self.view) #<-- problem is this single line
else :
...
except BaseException :
traceback.print_exc()
Please send your entire code so we can see what could be done
#code here
asyncio.sleep(10) #Will wait 10 seconds before sending
You can use the wait_for method to wait for the message to be edited. You can then use the message.edit method to edit the message and add the buttons.
import discord
from discord.ext import commands
from discord_components import DiscordComponents, Button, ButtonStyle
bot = commands.Bot(command_prefix="!")
DiscordComponents(bot)
#bot.command()
async def test(ctx):
message = await ctx.send("Hello")
await message.edit(content="Hello World")
await message.edit(components=[
Button(style=ButtonStyle.red, label="Red"),
Button(style=ButtonStyle.green, label="Green"),
Button(style=ButtonStyle.blue, label="Blue")
])
bot.run("token")
This uses discord-components, which you can get here:
https://devkiki7000.gitbook.io/discord-components
I'm trying to run Quart+Telethon with multiple clients. This example shows one global client. I have this working.
Now I need my app to handle multiple users simultaneously logging in and doing stuff.
This post suggests using asyncio.gather.
How do I need to change my code such that I can have multiple people logging in?
Here I placed the bulk of Quart functionality into the work() function (wherever client is referenced). In the def main() I start the app and then invoke asyncio.gather.
When running the app with two work() functions (two clients) in asyncio.gather I get error "AssertionError: Handler is overwriting existing for endpoint phone_form".
And if I run only with one work() function I get a different error: "ConnectionError('Cannot send requests while disconnected')"
What am I missing?
Thx
import os
import asyncio
from dotenv import load_dotenv
from quart import Quart, render_template_string, request, render_template
from telethon import TelegramClient
load_dotenv('.env')
API_ID = int(os.getenv('API_ID'))
API_HASH = str(os.getenv('API_HASH'))
app = Quart(__name__)
async def work(client):
async with client:
#app.route("/")
async def phone_form():
return await render_template('phone_form.html')
#app.route("/validation_form", methods=['POST'])
async def validation_form():
""" Ask the user for the confirmation code they just got. """
global phone
# Check form parameters (phone/code)
form = await request.form
if 'phone' in form:
phone = form['phone']
await client.send_code_request(phone)
return await render_template('validation_form.html', phone_nr=phone)
async def main():
import hypercorn.asyncio
# create task so that starting hypercorn server is no blocking functions that come after it
server = asyncio.create_task(hypercorn.asyncio.serve(app, hypercorn.Config()))
# have many clients here, using the app asynchronously
await asyncio.gather(
work(TelegramClient('user1', API_ID_, API_HASH)),
work(TelegramClient('user2', API_ID, API_HASH)),
)
# this is to start blocking - means after this subsequent functions will need to wait until hypercorn is finished (hypercorn runs forever!)
# this await also lets server run indefinitely
await server
if __name__ == '__main__':
asyncio.run(main())
The code is trying to set N function handlers to the same routes, that's what causing the error here. I believe you need a different approach here - make adding sessions a continuous process with routes dealing with the last (new) session.
I'm not sure how hypercorn server should be started so using it's part from your example.
eg.
API_ID = int(os.getenv('API_ID'))
API_HASH = str(os.getenv('API_HASH'))
app = Quart(__name__)
clients = []
async def work():
new_cli = None
phone = None
#app.route("/")
async def index():
""" Some page containing 'new session' button redirecting to /phone_form """
new_cli = None
phone = None
return render_template('index.html')
#app.route("/phone_form")
async def phone_form():
num = len(clients) + 1
new_cli = TelegramClient(f'user{num}', API_ID_, API_HASH)
await new_cli.connect()
return await render_template('phone_form.html')
#app.route("/validation_form", methods=['POST'])
async def validation_form():
""" Ask the user for the confirmation code they just got. """
# Check form parameters (phone/code)
form = await request.form
if 'phone' in form:
phone = form['phone']
await client.send_code_request(phone)
return await render_template('validation_form.html', phone_nr=phone)
#app.route("/confirm_code", methods=['POST'])
async def confirm_code():
""" Finish auth process. """
form = await request.form
if 'code' in form:
await new_cli.sign_in(phone, form['code'])
clients.append(new_cli)
new_cli = None
phone = None
async def main():
import hypercorn.asyncio
server = asyncio.create_task(hypercorn.asyncio.serve(app, hypercorn.Config()))
await work()
await server
if __name__ == '__main__':
asyncio.run(main())
You may also want to add checkers if new client session is present. Resulted sessions can be used later.
I'm a bit lost in what to do with this one, I have tried a couple of things but i can only get it to detect nickname changes within the server, which is not what i want
This is what I have:
#client.event
async def on_member_update(before, after):
if before.display_name != after.display_name:
embed = discord.Embed(colour=discord.Colour.from_rgb(162, 28, 29), title=f"Changed Username")
embed.add_field(name='Current Name', value=before.display_name)
embed.add_field(name='Old Name', value=after.display_name)
channel = client.get_channel(----------)
await channel.send(embed=embed)
yes, there is an event called on_user_update here is the example:
#client.event
async def on_user_update(before,after):
if before.name != after.name:
I'm trying to define a 'Payload' in Ruby for my Facebook Messenger bot. My use case is, when a user sees structured content (a story with a button) and they click the button, instead of sending them to a URL, I want to hit my webhook and return more structured content.
So, I've tried several iterations of this and not sure where I'm getting tripped up. I've started by adding a messaging event:
messaging_event["entry"].first["messaging"].each do |msg|
puts msg
sender = msg["sender"]["id"]
if msg["message"] && msg["message"]["text"]
payload = msg["message"][“payload”]
I did something very similar for adding text, which was:
post '/webhook/' do
messaging_event = JSON.parse(request.body.read)
puts messaging_event
messaging_event["entry"].first["messaging"].each do |msg|
puts msg
sender = msg["sender"]["id"]
if msg["message"] && msg["message"]["text"]
text = msg["message"]["text"]
puts "Sender ID: #{sender}, Text: #{text}"
So, at this point, I'm not sure if I need to further def the payload like:
def payload(sender, payload)
data = {
recipient: { id: sender },
message: payload
}
send_message(data)
end
Or, if I simply need to create a variable and call that variable within my Module object like:
module Messages
SIMPLE_ONE_BUTTON_PAYLOAD = {
"attachment":{
"type":"template",
"payload":{
"template_type":"button",
"text":"Here's a simple button message",
"buttons":[
"type":"postback",
"title":"Button One",
"payload":"[variable I need to call]",
]
}
}
}
end
So, there's really two things here -- Do I need the payload messaging event and to define the payload and what do I need to call within the object? Any thoughts or feedback here would be really helpful. Thanks in advance!
You need to handle postbacks in your code. When a user hits a button, facebook calls your webhook with a post back (unless it's a url).
From the docs:
Postbacks are back end calls to your webhook when buttons are tapped. These calls contain the payload that is set for the button. Buttons on Structured Messages support opening URLs and postbacks.
The structure of postback is different than a text message.
Text Message:
{"object":"page","entry":[{"id":654321,"time":1460624758100,"messaging":[{"sender":{"id":123456},"recipient":{"id":654321},"timestamp":1460624758089,"message":{"mid":"mid.987654","seq":12632,"text":"This is the message."}}]}]}
Postback:
{"object":"page","entry":[{"id":654321,"time":1460625294253,"messaging":[{"sender":{"id":123456},"recipient":{"id":654321},"timestamp":1460625294253,"postback":{"payload":"Payload defined in the button"}}]}]}
You're doing if msg["message"] && msg["message"]["text"] but a post back doesn't have the ["message"] element. You need to make another case for msg["postback"].
So, change this:
if msg["message"] && msg["message"]["text"]
payload = msg["message"]["payload"]
to this:
if msg["postback"] && msg["postback"]["payload"]
payload = msg["postback"]["payload"]
You can read further on handling postbacks here in the official documentation (Point 8 Handling Postbacks).
I'm building a web frontend to a server-side application, using Pylons 1.0.
Right now I'm writing the first form, and I'm facing a problem concerning validation.. Using FormEncode and the #validate decorator I can easily validate the user input from a client-side perspective, but when I submit the data to the server, it may perform additional checks and eventually throw back exceptions that I need to show to the user.
My question: is there a concise way to integrate/emulate this exception handling into the FormEncode/validate flow? For example, redisplay the form with filled fields and an error message, as would happen if the exception had come from the #validate itself?
Here's what I have at the moment:
def edit(self, id):
return render('/edit_user.mako')
#validate(schema=form.UserForm(), form="edit")
def add_user(self):
if request.POST:
u = helpers.load_attributes(User(), self.form_result)
try:
model.save_to_server(u)
except MyBaseException, exc:
helpers.flash(unicode(exc))
return self.edit()
In this way, in case of a server-side exception I can see the "flash" message but the form of course will have empty fields :/
I like to implement:
from formencode import htmlfill
def create(self):
if request.params:
try:
Post.validate(request.paramse)
post = helpers.load_attributes(Post(), request.params)
model.save_to_server(post)
flash('OK', 'success')
redirect(...)
except InvalidException as e:
for key, message in e.unpack_errors().iteritems():
flash(message, 'error')
return htmlfill.render(render('/blogs/create.html'), request.params)
where my Post.validate:
#staticmethod
def validate(data):
schema = PostSchema()
schema.to_python(data)
In this way, if is the first time (request.params empty) html fills form with nothing, when user send datas html fills form with request.params
Another way (inspired by this answer) is to write a decorator similar to #validate that would catch the desired exceptions and use htmlfill to display their message:
def handle_exceptions(form):
def wrapper(func, self, *args, **kwargs):
try:
return func(self, *args, **kwargs)
except MyBaseException, e:
request = self._py_object.request
errors = { "exception" : unicode(e) }
params = request.POST
decoded = params.mixed()
request.environ['REQUEST_METHOD'] = 'GET'
self._py_object.tmpl_context.form_errors = errors
request.environ['pylons.routes_dict']['action'] = form
response = self._dispatch_call()
# If the form_content is an exception response, return it
if hasattr(response, '_exception'):
return response
htmlfill_kwargs2 = {}
htmlfill_kwargs2.setdefault('encoding', request.charset)
return htmlfill.render(response, defaults=params, errors=errors,
**htmlfill_kwargs2)
return decorator(wrapper)
The decorator would be used like:
#handle_exceptions("edit")
#validate(schema=form.UserForm(), form="edit")
def add_user(self):
if request.POST:
u = helpers.load_attributes(User(), self.form_result)
model.save_to_server(u)