telegram price bot - function loop - telegram-bot

I am trying to make a telegram price bot but I am running into an issue.
works fine, but I can't set the bot to send me the updated price every 5 minutes (or more).
Any solution?
Thanks!
my code
import telegram
from telegram.ext import Updater
from telegram.ext import CommandHandler
from tracker import get_prices
telegram_bot_token = "mybot"
updater = Updater(token=telegram_bot_token, use_context=True)
dispatcher = updater.dispatcher
def start(update, context):
chat_id = update.effective_chat.id
message = ""
crypto_data = get_prices()
for i in crypto_data:
coin = crypto_data[i]["coin"]
price = crypto_data[i]["price"]
change_day = crypto_data[i]["change_day"]
change_hour = crypto_data[i]["change_hour"]
message += f" {coin}={price:,.5f}$ \nHour Change: {change_hour:.3f}%\nDay Change: {change_day:.3f}%\n\n"
context.bot.send_message(chat_id=chat_id, text=message)
dispatcher.add_handler(CommandHandler("start", start))
updater.start_polling()

Use a different bot, like for example #GroupHelpBot, with built-in capability to automate the execution. For more details, please also check: How to loop inside a custom Telegram bot?

Related

Python Telegram Bot ConversationHandler not working with webhook

I want to make a ConversationHandler in my bot that is using a webhook, the ConversationHandler only runs the function at the entry point, after that neither does it run the state function, nor does it run the fallback function. This CommandHandler runs fine when bot is run by polling.
ConversationHandler:
conv_handler = ConversationHandler(
entry_points=[CommandHandler("start", start)],
states={
NEW_PROJECT: [CallbackQueryHandler(project_name)],
PROJECT_NAME: [MessageHandler(Filters.regex(".*"), store_name_maybe_project_type)],
PROJECT_TYPE: [CallbackQueryHandler(store_type_maybe_admin)]
},
fallbacks=[CommandHandler('cancel', cancel)],
)
All the required functions:
def start(update, context):
# Gives button of add project
# We can use for loop to display buttons
keyboard = [
[InlineKeyboardButton("Add Project", callback_data="add_project")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("You have no projects right now.", reply_markup=reply_markup)
# if existing project then PROJECT or else NEW_PROJECT
return NEW_PROJECT
def project_name(update, context):
# asks for project name
query = update.callback_query
update.message.reply_text(text="Okay, Please enter your project name:")
return PROJECT_NAME
def store_name_maybe_project_type(update, context):
# stores project name and conditionally asks for project type
print(update.message.text)
keyboard = [
[InlineKeyboardButton("Telegram Group", callback_data="group")],
[InlineKeyboardButton("Telegram Channel", callback_data="channel")]
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text("What do you want to make?", reply_markup=reply_markup)
return PROJECT_TYPE
def store_type_maybe_admin(update, context):
# stores project type and conditonally asks for making admin
print(update.message.text)
keyboard = [[InlineKeyboardButton("Done", callback_data="done")]]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text(f"Make a private {update.message.text} and make this bot the admin", reply_markup=reply_markup)
return ConversationHandler.END
def cancel(update, context):
update.message.reply_text("Awww, that's too bad")
return ConversationHandler.END
This is how I set up the webhook(I think the problem is here somewhere):
#app.route(f"/{TOKEN}", methods=["POST"])
def respond():
"""Run the bot."""
update = telegram.Update.de_json(request.get_json(force=True), bot)
dispatcher = setup(bot, update)
dispatcher.process_update(update)
return "ok"
The setup function
def setup(bot, update):
# Create bot, update queue and dispatcher instances
dispatcher = Dispatcher(bot, None, workers=0)
##### Register handlers here #####
bot_handlers = initialize_bot(update)
for handler in bot_handlers:
dispatcher.add_handler(handler)
return dispatcher
And then I manually setup the webhook by using this route:
#app.route("/setwebhook", methods=["GET", "POST"])
def set_webhook():
s = bot.setWebhook(f"{URL}{TOKEN}")
if s:
return "webhook setup ok"
else:
return "webhook setup failed"
The add project button doesn't do anything.
ConversationHandler stores the current state in memory, so it's lost once the conv_handler reaches the end of it's lifetime (i.e. the variable is deleted or the process is shut down). Now your snippets don't show where you initialize the ConversationHandler, but I have the feeling that you create it anew for every incoming update - and every new instance doesn't have the knowledge of the previous one.
I have that feeling, because you create a new Dispatcher for every update as well. That's not necessary and in fact I'd strongly advise against it. Not only does it take time to initialize the Dispatcher, which you could save, but also if you're using chat/user/bot_data, the data get's lost every time you create a new instance.
The initialize_bot function is called in setup, where you create the new Dispatcher, which is why my guess would be that you create a new ConversationHandler for every update. Also it seems odd to me that the return value of that function seems to be dependent on the update - the handlers used by your dispatcher should be fixed ...
Disclaimer: I'm currently the maintainer of python-telegram-bot

Pika SelectConnection adapter 'Unresolved attribute reference'

I have a problem with connection to RabbitMQ using pika.SelectConnection adapter. I am using Pika 1.1.0 and Python 3.7.9, development using PyCharm Community.
Below snapshot of my code showing how I am creating connection.
import pika
def on_done():
connect.channel()
print("Open Callback")
if __name__ == '__main__':
account = "user"
password = "password"
server = "172.17.0.5"
credentials = pika.PlainCredentials(account, password)
parameters = pika.ConnectionParameters(host=server, port=15672, credentials=credentials, socket_timeout=10)
connect = pika.SelectConnection(parameters, on_open_callback=on_done)
connect.ioloop.start()
RabbitMQ is running, I have checked connection and messaging using pika.BlockingConnection adapter.
My IDE (PyCharm) is highliting start() function as "Unresolved attribute reference 'start' for class 'object'". When I run this code, there is no error. On admin webpage I don't see that connection is opened.
Has somebody meet similar problem? Something is wrong with my IDE?
Thank you for answer.
Just had the same warning, but in the AsyncPublisher-Example and I also wanted to get rid of it.
The problem is that the IOLoop is not specifically defined by pika, even though it should.
If you work with pika, the type of IOLoop you are looking for is:
pika.adapters.select_connection.IOLoop
In your case it would be the easiest to cast your IOLoop and then use this one to start.
io_loop = cast(pika.adapters.select_connection.IOLoop, connect.ioloop)
io_loop.start()
For the more complex AsyncPublisher I did pretty much the same thing:
def __init__(self, amqp_url: str, queues: List[str], interval: float):
self._ioloop: Optional[pika.adapters.select_connection.IOLoop] = None
And after the connection is established:
def run(self):
"""Run the example code by connecting and then starting the IOLoop.
"""
while not self._stopping:
self._connection = None
self._deliveries = []
self._ack = 0
self._not_ack = 0
self._message_number = 0
try:
self._connection = self.connect()
self._ioloop = cast(pika.adapters.select_connection.IOLoop, self._connection.ioloop)
self._ioloop.start()

Can we use two MTProto connections in a single app?

Hello I am trying to run both "userbot" and "bot account" in a single app (worker).
These two connections are namely tbot[main bot] and ubot[userbot]. For example:
tbot = TelegramClient("myapp", API_KEY, API_HASH)
tbot.start(bot_token=TOKEN)
ubot = TelegramClient(StringSession(STRING_SESSION), API_KEY, API_HASH)
ubot.start()
But the problem is these two connections can't run simultaneously, both the connections quits just after the first (tbot) starts
Anything I can do here ?
Try to use python threading for that
import threading
# ...
tbot = TelegramClient("myapp", API_KEY, API_HASH)
tbot_thread = threading.Thread(target=tbot.start, kwargs={'bot_token': TOKEN})
tbot_thread.start()
ubot = TelegramClient(StringSession(STRING_SESSION), API_KEY, API_HASH)
ubot_thread = threading.Thread(target=ubot.start)
ubot_thread.start()
So each client will start separately in separate Thread instead of waiting in the main thread. If anything else fails - see logs.

Use of RabbitTemplate.convertSendAndReceive with org.springframework.messaging.Message

I have successfully used the following to send an org.springframework.amqp.core.Message and receive a byte []
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
Message message =
MessageBuilder.withBody(payload)..setCorrelationIdString(id).build();
byte [] response = (byte[]) rabbitTemplate.convertSendAndReceive(message,m -> {
m.getMessageProperties().setCorrelationIdString(id);
This works fine if the queues are set up to handle the message correctly for Message<?>. But I have a series of queues that use the message type org.springframework.messaging.Message specifically Message<String>.
Is there a way I can use rabbitTemplate.convertSendAndReceive to send the org.springframework.messaging.Message Message< String>. Such that the following would work.
import org.springframework.messaging.Message;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
Message<String> message =
MessageBuilder.withPayload(payload).setCorrelationId(id).build();
Object returnObject = rabbitTemplate.convertSendAndReceive(message);
I have looked at the MessageConverter but I am unsure if I can use that.
Alternatively, should I use org.springframework.messaging.core.GenericMessagingTemplate.convertSendAndReceive
UPDATE.
I can make it work if I change what I have on the queues from
#Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
public Message<String> transform(Message<String> inMessage) {
to
#Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
public Message<String> transform(Message<?> inMessage) { GenericMessage<?>
genericMessage = (GenericMessage<?>)inMessage.getPayload();
String payload = (String)genericMessage.getPayload();
but I would rather not have to change the transformers to make this work as the code in question is for integration tests and existing code already works with what I already have.
END UPDATE
I think I have given enough information but please let me know if more details are required. Ideally, I am looking for a code example or to point me to the documentation that answers my question.
Use the RabbitMessagingTemplate documentation here.
public Message<?> sendAndReceive(String exchange, String routingKey, Message<?> requestMessage)

Scrapy: How to send data to the pipeline from a custom filter without downloading

To catch all redirection paths, including when the final url was already crawled, I wrote a custom duplicate filter:
import logging
from scrapy.dupefilters import RFPDupeFilter
from seoscraper.items import RedirectionItem
class CustomURLFilter(RFPDupeFilter):
def __init__(self, path=None, debug=False):
super(CustomURLFilter, self).__init__(path, debug)
def request_seen(self, request):
request_seen = super(CustomURLFilter, self).request_seen(request)
if request_seen is True:
item = RedirectionItem()
item['sources'] = [ u for u in request.meta.get('redirect_urls', u'') ]
item['destination'] = request.url
return request_seen
Now, how can I send the RedirectionItem directly to the pipeline?
Is there a way to instantiate the pipeline from the custom filter so that I can send data directly? Or shall I also create a custom scheduler and get the pipeline from there but how?