Subscription with selector does not work from python - stomp.py - python

I have run into a problem where a Python subscriber using stomp (stomp.py) with a message selector does not receive the messages it should. Interestingly enough, it appears to me at least that the problem is somehow with the sending of the message and not the subscription.
I am using ActiveMQ.
Here's the subscriber code:
class Listener(object):
def __init__(self, count):
if count <= 0:
count = float('inf')
self.count = count
def on_error(self, headers, message):
print("=" * 72)
print('RECEIVED AN ERROR.')
print('Message headers:')
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(headers)
print('Message body:')
print(message)
def on_message(self, headers, message):
print("=" * 72)
print('Message headers:')
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(headers)
print('Message body:')
print(message)
def main():
global conn
args = parse_args()
conn = stomp.Connection([(args.host, args.port)])
conn.set_listener('Listener', Listener(args.count))
conn.start()
conn.connect(login=args.user, passcode=args.password)
if (args.selector):
conn.subscribe(
destination=args.destination,
id=1,
ack='auto',
headers={'selector': args.selector}
)
else:
conn.subscribe(
destination=args.destination,
id=1,
ack='auto'
)
Now I can run this subscriber with a selector such as "type = 'test'".
If I publish a message using Java JMS, the message is received just fine. However, if I publish the identical message from Python it is not.
Here's the relevant Python publishing code:
headers = {}
headers['type'] = 'test'
conn = stomp.Connection12([(args.host, args.port)], auto_content_length=False)
conn.start()
conn.connect(login=args.user, passcode=args.password)
conn.send(body=body, headers=headers, destination=args.destination)
conn.disconnect()
print 'Message sent.'
Some interesting notes from my testing and debugging:
Running the subscriber with a selector receives a matching message sent from Java JMS but not from Python.
Running the subscriber with no selector receives a message sent from Java and also a message sent from Python.

fairly old, but I was currently facing the same issue and so I would like to leave a possible solution here.
At first, according to the documentation, you can provide a field called selectorwith SQL like syntax and should be part of the headers. In your example:
headers = {}
headers['selector'] = "type='test'"
conn = stomp.Connection12([(args.host, args.port)], auto_content_length=False)
conn.start()
conn.connect(login=args.user, passcode=args.password)
conn.send(body=body, headers=headers, destination=args.destination)
conn.disconnect()
print 'Message sent.'
I was also facing the error, that I could not receive any message send from JMS, but after a lot of reading, I found here, that there is a field name JMSType. I changed the code to
headers['selector'] = "type='test' OR JMSType='test'"
With that JMSType in there everything works like expected. Hope that helps somebody

Related

Custom on_message method with fast-api mqtt

I want to combine REST with MQTT. I am using fastapi_mqtt and fastapi.
I want to handle messages from specfic topics ( my code is below, some methods are copied from fastapi-mqtt documentation https://sabuhish.github.io/fastapi-mqtt/mqtt/). I realized that no if statement actually works in on_message method, only print which is outside of on_message. Do you have any idea why? And how to manage custom on_message handler?
import logging
import requests
from fastapi import FastAPI
from fastapi_mqtt import FastMQTT, MQTTConfig
url = '127.0.0.1:8000' # im testing on my local broker
settings = get_settings()
app = FastAPI(title="System Controller")
mqtt_config = MQTTConfig(
host = settings.mqtt_host,
port= settings.mqtt_port,
username=settings.mqtt_user,
password=settings.mqtt_password
)
mqtt = FastMQTT(
config=mqtt_config)
mqtt.init_app(app)
async def publish():
mqtt.publish("/mqtt", "Hello from Fastapi") #publishing mqtt topic
return {"result": True,"message":"Published" }
#mqtt.on_connect()
def connect(client, flags, rc, properties):
# subscribing mqtt topic
if rc == 0:
print('Connected to MQTT Broker')
mqtt.client.subscribe("#")
print("Connected: ", client, flags, rc, properties)
else:
print('Failed to connect, return code %d\n',rc)
def test_events_handler(client, topic, payload):
# topic stucture /test/{sub_topic}/{device_id}
device_id = topic.split('/')[2]
sub_topic = topic.split('/')[1]
msg = payload.decode()
if sub_topic == '1':
logging.debug(f'Received level message from {device_id}')
try:
PARAMS = {'level': msg}
r = requests.get(url = f'{url}/test/msg', params=PARAMS)
data = r.json()
print(data)
except:
print('Level value is not correct')
elif sub_topic =='2':
print(f'Received dose message from user. Send to {device_id}')
else:
print('There is no handler to that topic')
def topic_handler(client, topic, payload):
if topic.startswith('/test'):
# handling topics related to feeder device
tests_events_handler(client, topic, payload)
print("Received message: ",topic, payload.decode())
elif topic.startswith('/nexttest'):
pass
#mqtt.on_message()
async def message(client, topic, payload, qos, properties):
print(topic)
topic_handler(client, topic, payload)
#mqtt.subscribe("#")
async def message_to_topic(client, topic, payload, qos, properties):
print("Received message to specific topic: ", topic, payload.decode(), qos, properties)
#mqtt.on_disconnect()
def disconnect(client, packet, exc=None):
print("Disconnected")
#mqtt.on_subscribe()
def subscribe(client, mid, qos, properties):
print("subscribed", client, mid, qos, properties)
#app.get('/')
async def func():
return {'result': True, 'message': 'Published'}
I want this program to works like that:
subscribes MQTT topics, lets say'/test/#' and '/nextest/#'. and on message from one of that topics it checks if message came from topic one or two and then reads the rest of the topic and depends on remaining part of the topic it sends specific get request to fast api.

Botframework send proactive message then string not empty

I have a problem sending proactive messages using the Bot Framework with Python.
First what I need is to get the message body from Outlook, and then the bot must send that as a message to all the chats where it was added.
To do that, first I created a new file and called it Email.py.
To read every incoming message body I simply used while true: and time.sleep()
Here is my code example:
import imaplib, email, getpass
from email import policy
import json
import time
imap_host = 'outlook.office365.com'
imap_user = 'xx#xx.com'
# init imap connection
mail = imaplib.IMAP4_SSL(imap_host, 993)
rc, resp = mail.login(imap_user, 'xxxxxx')
while True:
# select only unread messages from inbox
mail.select('Inbox')
status, data = mail.search(None, '(UNSEEN)')
if not data[0].split():
time.sleep(120)
# Bot message variable
Message_for_bot = ''
# for each e-mail messages
for num in data[0].split():
# get a single message and parse it by policy.SMTP (RFC compliant)
status, data = mail.fetch(num, '(RFC822)')
email_msg = data[0][1]
email_msg = email.message_from_bytes(email_msg, policy=policy.SMTP)
# print only message parts that contain text data
for part in email_msg.walk():
if part.get_content_type() == "text/plain":
for line in part.get_content().splitlines():
Message_for_bot += '\n' + line
print(Message_for_bot)
After I successfully created a program to read and print all incoming messages, I tried to build my bot. I found a proactive message bot on the Internet and used it as an example.
First I thought to just run this file with os in the background, but then my bot wasn't running. So then I tried adding an async function in the bot file but it didn't work. My bot just ignores that function. (Then I found the async functions in activity_handler.py, but I didn't find any that could help me.)
Then I tried adding an on_message_activity function and thought maybe it will start working if I call the bot like "#bot hi" for example in Teams. For that idea I must always run the while cycle and never stop the bot, but then I just get a message, and if there's a new incoming message then the bot doesn't write it anymore, and it's not a solution because if the bot is used for multiple chats then it simply doesn't work this way.
Then I try include my code on on_members_added_activity it seems working on azure test in web chat perfectly, but in teams after 1-2 messages stopping to work.
my code
async def on_members_added_activity(
self, members_added: [ChannelAccount], turn_context: TurnContext
):
imap_host = 'outlook.office365.com'
imap_user = 'xxxxxx#xxxxxx.com'
# init imap connection
mail = imaplib.IMAP4_SSL(imap_host, 993)
rc, resp = mail.login(imap_user, 'xxxxxx')
while True:
# select only unread messages from inbox
mail.select('Inbox')
status, data = mail.search(None, '(UNSEEN)')
if not data[0].split():
time.sleep(5)
# Bot message variable
Message_for_bot = ''
# for each e-mail messages
for num in data[0].split():
# get a single message and parse it by policy.SMTP (RFC compliant)
status, data = mail.fetch(num, '(RFC822)')
email_msg = data[0][1]
email_msg = email.message_from_bytes(email_msg, policy=policy.SMTP)
# print only message parts that contain text data
for part in email_msg.walk():
if part.get_content_type() == "text/plain":
for line in part.get_content().splitlines():
Message_for_bot += '\n' + line
await turn_context.send_activity(f"{Message_for_bot}")
for member in members_added:
if member.id != turn_context.activity.recipient.id:
await turn_context.send_activity(
"bot starting work..."
)
So maybe it's possible to send a message to wherever the bot is added (it needs to get this information somehow, maybe it's kept in the bot memory) whenever Message_for_bot is not empty.
All help will be appreciated.
As we have discussed some logic has to change
Move your code out of the on_members_added_activity function
Use Proactive concept to send the message
-Vinoth

Acknowledging pubsub messages through python synchronous pull does not work

With the python google-cloud-pubsub library, acknowledging messages through the subscriber.acknowledge() does not acknowledge my messages. My ack deadline is set at 30 seconds.
Here is my code:
from google.cloud import pubsub_v1
project_id = "$$$$"
subscription_name = "$$$$"
subscriber = pubsub_v1.SubscriberClient()
subscription_path = subscriber.subscription_path(project_id, subscription_name)
response = subscriber.pull(subscription_path, max_messages=10, timeout=15)
for msg in response.received_messages:
subscriber.acknowledge(subscription=subscription_path, ack_ids=[msg.ack_id])
Using google-cloud-pubsub==1.0.2
Any idea of what I'm doing wrong?
What I recommend you is referring to Synchronous Pull documentation, then run a sample code in Python to pull and acknowledge messages:
from google.cloud import pubsub_v1
project_id = "Your Google Cloud Project ID"
TODO subscription_name = "Your Pub/Sub subscription name"
subscriber = pubsub_v1.SubscriberClient()
subscription_path = subscriber.subscription_path(
project_id, subscription_name)
NUM_MESSAGES = 3
response = subscriber.pull(subscription_path, max_messages=NUM_MESSAGES)
ack_ids = []
for received_message in response.received_messages:
print("Received: {}".format(received_message.message.data))
ack_ids.append(received_message.ack_id)
subscriber.acknowledge(subscription_path, ack_ids)
print('Received and acknowledged {} messages. Done.'.format(
len(response.received_messages)))
I can't find definition of ack_ids = [] in your code (you need to define it before starting use it in code). If you will see positive results when running that piece of code, you can assume that there is a bug in your code. Have you provided a full code?

Deleting Messages in Slack

Sooo, I'm relatively new to programming, and trying to learn how to consume API's. I figured I would start out by building a Slack bot for moderation purposes since I use Slack a lot. For the most part, everything works except for when I try to delete a message. The API returns saying it can't find the message even though it is there in the channel (the slack API uses timestamps to locate said message). The timestamps match, but proclaims the message doesn't exist. Here is my code:
def __init__(self, token):
self.token = token
self.users = {}
self.channels = {}
self.slack = SlackClient(self.token)
self.as_user = True
def connect(self):
if self.slack.rtm_connect():
self.post_message('#test', "*AUTOMOD* _v0.1_")
while True:
# print(self.slack.rtm_read())
self.parse_data(self.slack.rtm_read())
time.sleep(1)
def parse_data(self, payload):
if payload:
if payload[0]['type'] == 'message':
print(("user: {} message: {} channel: {}").format(payload[0]['user'], payload[0]['text'], payload[0]['channel']))
self.handle_message(payload[0])
def handle_message(self, data):
# these users can post whatever they want.
WHITELISTED = ["U4DU2TS2F", "U3VSRJJD8", "U3WLZUTQE", "U3W1Q2ULT"]
# get userid
sent_from = (data['user'])
# ignore whitelisted
if sent_from in WHITELISTED:
return
# if message was sent from someone not in WHITELISTED, delete it
else:
print(("\n\ntimestamp of message: {}").format(data['ts']))
self.delete_message(data['channel'], data['ts'])
self.post_message(data['channel'], "```" + random.choice(dongers) + "```")
def delete_message(self, channel, timestamp):
print(("deleting message in channel '{}'...").format(channel))
print("timestamp check (just to make sure): ", timestamp)
deleted = self.slack.api_call("chat.delete",
channel=channel,
timestamp=timestamp,
as_user=self.as_user
)
if deleted.get('ok'):
print("\nsuccessfully deleted.\n")
else:
print(("\ncouldn't delete message: {}\n").format(deleted['error']))
OUTPUT
timestamp of message: 1488822718.000040
deleting message in channel: 'G4DGYCW2X'
timestamp check (just to make sure...): 1488822718.000040
couldn't delete message: message_not_found
Any ideas on what could be happening? Here is the chat.delete method for context.
EDIT:
Due #pvg's recommendation of "Minimal, Complete, and Verifiable example", I have placed the ENTIRE code from the project in a gist.
One issue might be that you appear to be passing a timestamp parameter to chat.delete, when the API method takes a ts parameter instead. (See docs)

How can I retrieve a Google Talk users Status Message

I'd like to be able to retrieve a users Google Talk Status Message with Python, it's really hard to find documentation on how to use some of the libraries out there.
I don't have anything to hand with xmpp installed, but here's some old code I had lying around that might help you. You'll want to update the USERNAME/PASSWORD to your own values for test purposes.
Things to note: users logged in to Google Talk get a random presence string on their userid: that doesn't matter if you are trying to get the status of some other user, but if you want to write some code so want to communicate with yourself you need to distinguish the user logged in from GMail or a GTalk client from the test program. Hence the code searches through the userids.
Also, if you read the status immediately after logging in you probably won't get anything. There's a delay in the code because it takes a little while for the status to become available.
"""Send a single GTalk message to myself"""
import xmpp
import time
_SERVER = 'talk.google.com', 5223
USERNAME = 'someuser#gmail.com'
PASSWORD = 'whatever'
def sendMessage(tojid, text, username=USERNAME, password=PASSWORD):
jid = xmpp.protocol.JID(username)
client = xmpp.Client(jid.getDomain(), debug=[])
#self.client.RegisterHandler('message', self.message_cb)
if not client:
print 'Connection failed!'
return
con = client.connect(server=_SERVER)
print 'connected with', con
auth = client.auth(jid.getNode(), password, 'botty')
if not auth:
print 'Authentication failed!'
return
client.RegisterHandler('message', message_cb)
roster = client.getRoster()
client.sendInitPresence()
if '/' in tojid:
tail = tojid.split('/')[-1]
t = time.time() + 1
while time.time() < t:
client.Process(1)
time.sleep(0.1)
if [ res for res in roster.getResources(tojid) if res.startswith(tail) ]:
break
for res in roster.getResources(tojid):
if res.startswith(tail):
tojid = tojid.split('/', 1)[0] + '/' + res
print "sending to", tojid
id = client.send(xmpp.protocol.Message(tojid, text))
t = time.time() + 1
while time.time() < t:
client.Process(1)
time.sleep(0.1)
print "status", roster.getStatus(tojid)
print "show", roster.getShow(tojid)
print "resources", roster.getResources(tojid)
client.disconnect()
def message_cb(session, message):
print ">", message
sendMessage(USERNAME + '/Talk', "This is an automatically generated gtalk message: did you get it?")

Categories

Resources