Tornado routes no picked up by Heroku - python

i follow the tutorial based on a service i wan't to use ( Drone Deploy) :
https://dronedeploy.gitbooks.io/dronedeploy-apps/content/server_example.html
i made a topic on their forum for this issue 2 days ago.( and repo on Github)
But maybe someone can help me here.
I got an issue with an Heroku server app i do.
i use Python and the Tornado module.
The fact is i got a 404 error
My terminal ( when test it localy ) ask me :
"WARNING:tornado.access:404 GET / (::1) 0.75ms"
so the "GET" function is not working , maybe because of HTTP access control (CORS) i try many fix , but none worked.
Maybe i made something wrong ,or forgot something.
update :
Recently someone of the Drone deploy said my tornado routes aren't being picked up by heroku.
After following many tutorial and read the Tornado documentation i have no idea how to routes this.
the url of the server : https://stardrone-server.herokuapp.com/
this the code :
import os
import requests
import tornado.ioloop
import tornado.web
GEOCODE_FMT = 'https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={key}'
class GeocodeHandler(tornado.web.RequestHandler):
"""Proxy a call to the Google Maps geocode API"""
def set_default_headers(self):
# allow cross-origin requests to be made from your app on DroneDeploy to your web server
self.set_header("Access-Control-Allow-Origin", "https://www.dronedeploy.com")
self.set_header("Access-Control-Allow-Headers", "x-requested-with")
# add more allowed methods when adding more handlers (POST, PUT, etc.)
self.set_header("Access-Control-Allow-Methods", "GET, OPTIONS")
def get(self):
api_key = os.environ.get("MyApiKey")
address = self.get_query_argument("address")
url = GEOCODE_FMT.format(address=address, key=api_key)
# fetch results of the geocode from Google
response = requests.get(url)
# send the results back to the client
self.write(response.content)
def options(self):
# no body
self.set_status(204)
self.finish()
def main():
application = tornado.web.Application([
(r"/geocode/", GeocodeHandler)
])
port = int(os.environ.get("PORT", 5000))
application.listen(port)
tornado.ioloop.IOLoop.current().start()
if __name__ == "__main__":
main()
Maybe i missed something.
Any help, advices are appreciated
Thanks
John

Related

Why am I getting a response from the wrong API endpoint?

I am following this tutorial initially I was trying to get a response using postman with the url
ec2-x-x-xxx-xx.eu-west-2.compute.amazonaws.com/:8080
but it would not return a response, so then I tried without the / at the end and it returned what I wanted, why is this happening as my flask route clearly has a / in it
My flask app looks like this
from flask import Flask
application = Flask(__name__)
#application.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == '__main__':
application.run(host="0.0.0.0", port="8080")
The order of the parts of a URL is important.
The URL
ec2-x-x-xxx-xx.eu-west-2.compute.amazonaws.com/:8080
Is going to attempt port 80, and look for a path /:8080.
ec2-x-x-xxx-xx.eu-west-2.compute.amazonaws.com:8080/
Will attempt port 8080 and look for a path /
There are two different concepts that you are getting mixed up on here.
The line #application.route("/") defines the root of your site. That is the default entry point or path if you enter your site address in a browser without e.g /about at the end.
The address ec2-x-x-xxx-xx.eu-west-2.compute.amazonaws.com:8080 is a combination of the web server address and port, separated by a colon. You will not get a response if you alter this address. You could add a "/" after the 8080 to get to a particular page.

Alexa - Python, There was an error calling the remote endpoint, which returned HTTP 404 : NOT FOUND

I am using flask with python to develop my code for an Alexa skill which fetched Wikipedia data. I am also using Wikipedia library of Python.
Every time I try to test my skill Service simulator gives an error. Please help me find the error.
"There was an error calling the remote endpoint, which returned HTTP 404 : NOT FOUND"
from flask import Flask
from flask_ask import Ask, statement, question, session
import json
import requests
import time
import unidecode
import wikipedia
app = Flask(__name__)
ask = Ask(app,"/wiki_reader")
def get_wikisummary(searchitem):
summ=wikipedia.summary(searchitem,sentences=3)
sober=[unidecode.unidecode(summ)]
return sober
#app.route('/')
def homepage():
return "hi there, how ya doin?"
#ask.launch
def start_skill():
welcome_message='Hi, ask me about any country of the World'
return question(welcome_message)
#ask.intent("AnswerIntent")
def answer(ans):
summ1=get_wikisummary(ans)
summ2=[unidecode.unidecode(summ1)]
return statement("{}",format(summ2))
if __name__=='__main__':
app.run(debug=True)
I am using ngrok to host code which is currently hosted on localhost, on my machine.
I just figured out I was trying to run multiple codes on a single port. This is why it was giving not found error.

Instagram Real-time API can't see my server

I'm testing the Instagram Real-time API with Python and Flask and I get everytime this response from the Instagram server:
{
"meta":{
"error_type":"APISubscriptionError",
"code":400,
"error_message":"Unable to reach callback URL \"http:\/\/my_callback_url:8543\/instagram\"."
}
}
The request:
curl -F 'client_id=my_client_id...' \
-F 'client_secret=my_client_secret...' \
-F 'object=tag' \
-F 'aspect=media' \
-F 'object_id=fox' \
-F 'callback_url=http://my_callback_url:8543/instagram' \
https://api.instagram.com/v1/subscriptions/
And this is the code of the Flask server:
from flask import Flask
from flask import request
from instagram import subscriptions
app = Flask(__name__)
CLIENT_ID = "my_client_id..."
CLIENT_SECRET = "my_client_secret..."
def process_tag_update(update):
print 'Received a push: ', update
reactor = subscriptions.SubscriptionsReactor()
reactor.register_callback(subscriptions.SubscriptionType.TAG, process_tag_update)
#app.route('/instagram', methods=['GET'])
def handshake():
# GET method is used when validating the endpoint as per the Pubsubhubub protocol
mode = request.values.get('hub.mode')
challenge = request.values.get('hub.challenge')
verify_token = request.values.get('hub.verify_token')
if challenge:
return challenge
return 'It is not a valid challenge'
#app.route('/instagram', methods=['POST'])
def callback():
# POST event is used to for the events notifications
x_hub_signature = request.headers.get('X-Hub-Signature')
raw_response = request.data
try:
reactor.process(CLIENT_SECRET, raw_response, x_hub_signature)
except subscriptions.SubscriptionVerifyError:
print 'Signature mismatch'
return 'done'
def server():
""" Main server, will allow us to make it wsgi'able """
app.run(host='0.0.0.0', port=8543, debug=True)
if __name__ == '__main__':
server()
The machine have a public IP and the port is open for everyone. I can reach the url from others networks.
Why can't Instagram reach my url? Is there a black list or something like that?
Update 1
I have tested the same code with some frameworks and WSGI servers (Django, Flask, Node.js, Gunicorn, Apache) and different responses in the GET/POST endpoint and I always get the same 400 error message.
Also I have checked the packages received in my network interface with Wireshark and I get the expected results with calls from any network. But I don't get any package when I do the subscription request.
So... Is this a bug? Could be my IP in any blacklist for some reason?
I had exactly the same. It worked when I accidentally restarted the router, getting a different IP. It seems that it could be an IP issue indeed and the Unable to reach callback URL... is not really helpful in this case.
I agree, there are plenty of AWS servers answering to that API and some are not working. Ping api.instagram.com and you'll see you get multiple and different IP for that domain name. There is a DNS round robin and you are not reaching the same server every time.
I've found one server (IP : 52.6.133.72) which seems to be working for subscription and have configured my server to use that one (by editing the /etc/hosts file). Not a reliable solution ... but it's working.

App Engine Backends Configuration (python)

I got timeout error on my GAE server when it tries to send large files to an EC2 REST server. I found Backends Python API would be a good solution to my example but I had some problems on configuring it.
Following some instructions, I have added a simple backends.yaml in my project folder. But I still received the following error, which seems like I failed to create a backend instance.
File "\Google\google_appengine\google\appengine\api\background_thread\background_thread.py", line 84, in start_new_background_thread
raise ERROR_MAP[error.application_error](error.error_detail)
FrontendsNotSupported
Below is my code, and my question is:
Currently, I got timeout error in OutputPage.py, how do I let this script run on a backend instance?
update
Following Jimmy Kane's suggestions, I created a new script przm_batchmodel_backend.py for the backend instance. After staring my GAE, now it I have two ports (a default and a backend) running my site. Is that correct?
app.yaml
- url: /backend.html
script: przm_batchmodel.py
backends.yaml
backends:
- name: mybackend
class: B1
instances: 1
options: dynamic
OutputPage.py
from przm import przm_batchmodel
from google.appengine.api import background_thread
class OutputPage(webapp.RequestHandler):
def post(self):
form = cgi.FieldStorage()
thefile = form['upfile']
#this is the old way to initiate calculations
#html= przm_batchmodel.loop_html(thefile)
przm_batchoutput_backend.przmBatchOutputPageBackend(thefile)
self.response.out.write(html)
app = webapp.WSGIApplication([('/.*', OutputPage)], debug=True)
przm_batchmodel.py
def loop_html(thefile):
#parses uploaded csv and send its info. to the REST server, the returned value is a html page.
data= csv.reader(thefile.file.read().splitlines())
response = urlfetch.fetch(url=REST_server, payload=data, method=urlfetch.POST, headers=http_headers, deadline=60)
return response
przm_batchmodel_backend.py
class BakendHandler(webapp.RequestHandler):
def post(self):
t = background_thread.BackgroundThread(target=przm_batchmodel.loop_html, args=[thefile])
t.start()
app = webapp.WSGIApplication([('/backend.html', BakendHandler)], debug=True)
You need to create an application 'file'/script for the backend to work. Just like you do with the main.
So something like:
app.yaml
- url: /backend.html
script: przm_batchmodel.py
and on przm_batchmodel.py
class BakendHandler(webapp.RequestHandler):
def post(self):
html = 'test'
self.response.out.write(html)
app = webapp.WSGIApplication([('/backend.html', OutputPage)], debug=True)
May I also suggest using the new feature modules which are easier to setup?
Edit due to comment
Possible the setup was not your problem.
From the docs
Code running on a backend can start a background thread, a thread that
can "outlive" the request that spawns it. They allow backend instances
to perform arbitrary periodic or scheduled tasks or to continue
working in the background after a request has returned to the user.
You can only use backgroundthread on backends.
So edit again. Move the part of the code that is:
t = background_thread.BackgroundThread(target=przm_batchmodel.loop_html, args=[thefile])
t.start()
self.response.out.write(html)
To the backend app

How to make an authenticated request from a script to appengine?

How do I make an authenticated request from a python script to appengine? I have found lots of different methods on the web but none work.
E.G. How do you access an authenticated Google App Engine service from a (non-web) python client? doesn't work, the request returns the login page.
That post is old, maybe something changed since then.
Has anyone got a nice wrapped object to do this?
Answered my own question:
from google.appengine.tools import appengine_rpc
use_production = True
if use_production:
base_url = 'myapp.appspot.com'
else:
base_url = 'localhost:8080'
def passwdFunc():
return ('user#gmail.com','password')
def main(argv):
rpcServer = appengine_rpc.HttpRpcServer(base_url,
passwdFunc,
None,
'myapp',
save_cookies=True,
secure=use_production)
# Makes the actual call, I guess is the same for POST and GET?
blah = rpcServer.Send('/some_path/')
print blah
if __name__ == '__main__':
main(sys.argv)
You can see one example of a non-web authenticated python client making requests in the Python client library used to process GAE Pull Queues at https://developers.google.com/appengine/docs/python/taskqueue/overview-pull#Using_the_Task_Queue_REST_API_with_the_Python_Google_API_Library

Categories

Resources