I have a two part python standalone application: a publisher and a subscriber.
The publisher generates fake JSON devices objects and published them on a channel called "devices." And as you would guess, the subscriber subscribes to the channel "devices."
(Additionally, given optional command line arguments, the publisher or subscriber can write JSON objects to a socket or a local directory where an Apache Spark Streaming context pickups the JSON objects and processes it. For now, this is not in the picture, as it's optional.)
However, my problem is when my subscriber runs, after the publisher has finished, I get "ERROR: Forbidden".
Here are the respective python code snippets for the publisher:
pubnub = Pubnub(publish_key="my_key", subscribe_key="my_key")
....
pubnub.publish(ch, device_msg)
In the subscriber python file I have the following init code:
def receive(message, channel):
json.dumps(message)
def on_error(message):
print ("ERROR: " + str(message))
....
pubnub = Pubnub(publish_key="my_keys", subscribe_key="my_keys")
# subscribe to a channel and invoke the appropriate callback when a message arrives on that
# channel
#
pubnub.subscribe(channels=ch, callback=receive, error=on_error)
pubnub.start()
While the publisher, when run, seems to publish the JSON messages, all 120 in a loop, whereas the subscriber, when run, seems to fail with the following error message:
ERROR: Forbidden
My attempts to use "demo" keys have made no difference. Note that I'm using a trial account for PubNub.
Since this is one of my first app using its API, has anyone seen this problem before. Surely, something very obvious or trivial is amiss here.
Answer was that there was a copy/paste error with the pub/sub keys.
Related
I want to send a message to a websocket client when it connects to the server on AWS lambda and API gateway. Currently, I use wscat as a client. Since the response 'connected' is not shown on the wscat console when I connect to the server, I added post_to_connection to send a message 'hello world' to the client. However, it raises GoneException.
An error occurred (GoneException) when calling the PostToConnection
operation
How can I solve this problem and send some message to wscat when connecting to the server?
My python code is below. I use Python 3.8.5.
import os
import boto3
import botocore
dynamodb = boto3.resource('dynamodb')
connections = dynamodb.Table(os.environ['TABLE_NAME'])
def lambda_handler(event, context):
domain_name = event.get('requestContext',{}).get('domainName')
stage = event.get('requestContext',{}).get('stage')
connection_id = event.get('requestContext',{}).get('connectionId')
result = connections.put_item(Item={ 'id': connection_id })
apigw_management = boto3.client('apigatewaymanagementapi',
endpoint_url=F"https://{domain_name}/{stage}")
ret = "hello world";
try:
_ = apigw_management.post_to_connection(ConnectionId=connection_id,
Data=ret)
except botocore.exceptions.ClientError as e:
print(e);
return { 'statusCode': 500,
'body': 'something went wrong' }
return { 'statusCode': 200,
"body": 'connected'};
Self-answer: you cannot post_to_connection to the connection itself in onconnect.
I have found that the GoneException can occur when the client that initiated the websocket has disconnected from the socket and its connectionId can no longer be found. Is there something causing the originating client to disconnect from the socket before it can receive your return message?
My use case is different but I am basically using a DB to check the state of a connection before replying to it, and not using the request context to do that. This error's appearance was reduced by writing connectionIds to DynamoDB on connect, and deleting them from the table upon disconnect events. Messaging now writes to connectionIds in the table instead of the id in the request context. Most messages go through but some errors are still emitted when the client leaves the socket but does not emit a proper disconnect event which leaves orphans in the table. The next step is to enforce item deletes when irregular disconnections occur. Involving a DB may be overkill for your situation, just sharing what helped me make progress on the GoneException error.
We need to post to connection after connecting (i.e. when the routeKey is not $connect)
routeKey = event.get('requestContext', {}).get('routeKey')
print(routeKey) # for debugging
if routeKey != '$connect': # if we have defined multiple route keys we can choose the right one here
apigw_management.post_to_connection(ConnectionId=connection_id, Data=ret)
#nemy's answer is totally true but it doesn't explain the reason. So, I just want to explain...
So, first of all What is GoneException or GoneError 410 ?
A 410 Gone error occurs when a user tries to access an asset which no longer exists on the requested server. In order for a request to return a 410 Gone status, the resource must also have no forwarding address and be considered to be gone permanently.
you can find more details about GoneException in this article.
In here, GoneException has occured; it means that the POST connection we are trying to make, doesn't exist - which fits perfectly in the scenario. Because we still haven't established the connection between Client and Server. The way APIGatewayWebsocketAPIs work is that you request an Endpoint(Route) and that Endpoint will invoke that Lambda Function (In our case it is ConnectionLambdaFunction for $connect Route).
Now, if The Lambda function resolves with statusCode: 200 then and only then the API Gateway will allow the connection to be established. So, basically untill we return statusCode: 200 from our Lambda Function we are not connected and untill then we are totally unknown to server and thats why the Post call that has been made before the return statement itself will throw an error.
I am new to Microsoft Bot Framework, I am learning it through a youtube video https://youtu.be/ynG6Muox81o and making my bot on python3 on Ubuntu.
The Microsoft Bot Emulator says "sending failed. Retry".
Visual Studio Code shows KeyError: 'HTTP_CONTEXT_TYPE'.
I did everything right, my bot is connected to http://localhost:3978/, and bot emulator is connected to http://localhost:3978/api/messages/.
Many people on stackoverflow who had the same issue faced it due to windows firewall, but mine is ubuntu and i did check if it was enabled but its not.
app.py
from flask import Flask, request, Response
from botbuilder.schema import Activity
from botbuilder.core import BotFrameworkAdapter,BotFrameworkAdapterSettings
import asyncio
from echobot import EchoBot
app = Flask(__name__)
loop = asyncio.get_event_loop()
botadaptersettings=BotFrameworkAdapterSettings("","")
botadapter = BotFrameworkAdapter(botadaptersettings)
ebot = EchoBot()
#POST is the message
#app.route("/api/messages",methods=["POST"])
def messages():
#checking if HTTP file format is JSON or not
if "application/json" in request.headers["context-type"]:
#reading the JSON message
jsonmessage = request.json
else:
#unsupported media type 415
return Response(status=415)
activity = Activity().deserialize(jsonmessage)
async def turn_call(turn_context):
await ebot.on_turn(turn_context)
task = loop.create_task(botadapter.process_activity(activity,"",turn_call))
loop.run_until_complete(task)
if __name__ == '__main__':
app.run('localhost',3978)
echobot.py
from botbuilder.core import TurnContext
class EchoBot:
async def on_turn(self,turn_context:TurnContext):
await turn_context.send_activity(turn_context.activity.text)
I cant seem to understand the issue and how to fix it. it would be really helpfull if someone could help me fix this as i am really interested in building bots.
I have uploaded my Bot Project on gitlab https://gitlab.com/pdmnbhrawal/myechobot01.
This is a simple typo. You've written "context-type" instead of "content-type." The YouTube tutorial you linked to tells you to write a line like this:
if "application/json" in request.headers["content-type"]:
In order to avoid this kind of typo, you can download the source code that the video links to directly instead of trying to rewrite it yourself.
You can troubleshoot this kind of error yourself by noticing in the stack trace that it tells you what line of code is throwing the error. When it says KeyError: 'HTTP_CONTEXT_TYPE' that should indicate to you that you've entered the wrong key and you should check for a typo. You can also try using a debugger and stepping through your code.
There are a few other problems with the bot that you may notice. It doesn't handle conversation update activities correctly because it doesn't account for the incoming activity having no text. It also doesn't return an HTTP response from the api/messages endpoint. You might want to fix those problems later, but your bot will run despite them.
I want to write a simple slack bot, which responds a given string to # mentions, however I am not able to make the official documentation code to work.
I gave all OAuth permission to the bot and have the following code:
from slack import RTMClient
#RTMClient.run_on(event="message")
def gravity_bot(**payload):
data = payload['data']
print(data.get('text'))
try:
rtm_client = RTMClient(
token="my_token_auth_code",
connect_method='rtm.start'
)
print("Bot is up and running!")
rtm_client.start()
except Exception as err:
print(err)
I think the connection is established, as the "Bot is up and running" message appears, however on the slack channel to bot seems to be offline, also I am not able to get any response in the terminal, not for direct messages, not for channel messages even after inviting the bot to given channels.
Sorry couldn't let this one go.. I figured it out and here are the steps:
Create a "Classic" app in Slack (this is the only way to get the appropriate scopes), just click this link: https://api.slack.com/apps?new_classic_app=1
From the "Add features and functionality" tab click on "bots":
Click the "Add Legacy Bot User" button (this will add the "rtm.stream" scope that you need, but that you cannot add manually)
From the basic information page, install your app in a workspace
From the OAuth & Permissions page, copy the "Bot User OAuth Access Token" (the bottom one)
Run the following code (slightly modified version of the code in the docs)
from slack_sdk.rtm import RTMClient
# This event runs when the connection is established and shows some connection info
#RTMClient.run_on(event="open")
def show_start(**payload):
print(payload)
#RTMClient.run_on(event="message")
def say_hello(**payload):
print(payload)
data = payload['data']
web_client = payload['web_client']
if 'Hello' in data['text']:
channel_id = data['channel']
thread_ts = data['ts']
user = data['user']
web_client.chat_postMessage(
channel=channel_id,
text=f"Hi <#{user}>!",
thread_ts=thread_ts
)
if __name__ == "__main__":
slack_token = "<YOUR TOKEN HERE>"
rtm_client = RTMClient(token=slack_token)
rtm_client.start()
Previous answer:
Hmm, this is tricky one... According to the docs this only works for "classic" Slack apps, so that might be the first pointer. It explicitly says that you should not upgrade your app. Furthermore, you'll need to set the right permissions (god knows which ones) by selecting the "bot" scope.
Honestly, I haven't been able to get this running. Looks like Slack is getting rid of this connection method, so you might have more luck looking into the "Events API". I know it's not the ideal solution because its not as real-time, but it looks better documented and it will stay around for a while. Another approach could be polling. Its not sexy but it works...
My guess is that your problem is that there is not a valid connection, but there is no proper error handling in the Slack library. The message is printed before you actually connect, so that doesn't indicate anything.
I'm using the sdk of the service bus to send to a queue and listen for the answer in another, but I can not find valid examples of how to make that flow. My biggest difficulty is being able to set reply_to and reply_to_group_id, as I did in the old versions directly in the MessageProperties, now in the class Message I am in doubt with what to inform in the index 'message' to achieve this objective
The Message class has a property called properties which is an instance of uamqp.message.MessageProperties which has the reply_to (and reply_to_group_id) property that you are looking for.
from azure.servicebus import Message
message = Message(
body="Hello World!"
)
message.properties.reply_to="replyTo"
message.properties.reply_to_group_id="replyGroupId"
You can read more about AMQP Request-Response Operations with Service Bus in the docs.
to add to #pramodValavala's answer, here's how you do it with the v7.0 https://pypi.org/project/azure-servicebus/7.0.0/
from azure.servicebus import ServiceBusMessage
message = ServiceBusMessage("hello world")
# set using application_properties
message.application_properties = {'reply_to': 'abc'}
This is a very specific question, but I cannot find any documentation on how I can do it. The Facebook Documentation is pretty vague with some horrible and useless PHP examples (really, it's code like the Facebook PHP Sample Code that make people think PHP sucks) but I cannot find anything around for Python.
I can't even work out how to apply the same principles from the PHP sample code into a Python world. The xmpppy and SleekXMPP docs are a bit bare (or broken) and Google only shows examples of people using passwords.
I have the access tokens coming from the database, I have no interest in spawning a browser to find stuff, or doing anything else to find a token. I have them, consider it a hardcoded string. I want to pass that string to XMPP and send a message, that is the whole scope of things.
Any suggestions?
The below code worked, but only after some modifications mentioned in this thread
I answered this with a link to a blog I wrote because it described the solution perfectly, but apparently that annoyed some moderators.
While that's clearly ridiculous, here is the answer reposted.
import sleekxmpp
import logging
logging.basicConfig(level=logging.DEBUG)
class SendMsgBot(sleekxmpp.ClientXMPP):
def init(self, jid, recipient, message):
sleekxmpp.ClientXMPP.__init__(self, jid, 'ignore')
# The message we wish to send, and the JID that
# will receive it.
self.recipient = recipient
self.msg = message
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start, threaded=True)
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient, mbody=self.msg, mtype='chat')
# Using wait=True ensures that the send queue will be
#emptied before ending the session.
self.disconnect(wait=True)
I shoved that in a file called fbxmpp.py, then in another file (your worker, your command line app, your Flask controller, whatever) you'll need something like the following:
from fbxmpp import SendMsgBot
# The "From" Facebook ID
jid = '511501255#chat.facebook.com'
# The "Recipient" Facebook ID, with a hyphen for some reason
to = '-1000023894758#chat.facebook.com'
# Whatever you're sending
msg = 'Hey Other Phil, how is it going?'
xmpp = SendMsgBot(jid, to, unicode(msg))
xmpp.credentials['api_key'] = '123456'
xmpp.credentials['access_token'] = 'your-access-token'
if xmpp.connect(('chat.facebook.com', 5222)):
xmpp.process(block=True)
print("Done")
else:
print("Unable to connect.")